开发网站需要什么语言,网页制作期末作业,举报网站平台怎么举报,资源网站搭建1、RBAC权限模型
RBAC#xff08;Role-Based Access Control#xff09;是一种基于角色的访问控制模型#xff0c;用于管理系统中用户的权限和访问控制。它将用户、角色和权限之间的关系进行了明确的定义#xff0c;以实现灵活的权限管理和控制。
1.1、RBAC模型主要包括以…1、RBAC权限模型
RBACRole-Based Access Control是一种基于角色的访问控制模型用于管理系统中用户的权限和访问控制。它将用户、角色和权限之间的关系进行了明确的定义以实现灵活的权限管理和控制。
1.1、RBAC模型主要包括以下几个核心概念
1、模型概念
用户User系统中的实际操作者拥有唯一标识符。
角色Role权限的集合可以被赋予给用户一个用户可以拥有一个或多个角色。
权限Permission系统中的具体操作权限定义了用户可以执行的操作可以是功能菜单的接口路径URL也可以是其他细粒度的操作权限。
2、操作概念
授权Authorization将权限赋予用户或角色的过程即为用户分配相应的角色或权限。
认证Authentication验证用户的身份和权限确保用户具有访问系统资源的合法权限。
RBAC模型的基本原则是权限授权应该基于角色而不是直接授权给特定用户。通过角色的中介将权限与用户进行解耦实现了权限的集中管理和灵活分配。
1.2、RBAC模型的优点包括
简化权限管理通过角色的授权机制可以集中管理和维护权限减少了权限管理的复杂性。灵活的权限分配通过给用户分配适当的角色可以灵活地控制用户的权限实现细粒度的访问控制。易于扩展和维护RBAC模型具有良好的可扩展性和维护性可以根据业务需求进行权限的增删改操作而不影响其他部分的权限控制。
在实际应用中RBAC模型可以结合权限管理框架和安全框架来实现。例如使用Spring Security框架可以方便地实现RBAC模型的权限控制通过定义角色、权限和用户的关系并结合注解和配置来实现权限的校验和访问控制。
总结来说RBAC模型是一种灵活和可扩展的权限管理模型通过角色的授权机制实现了权限的集中管理和灵活分配为系统提供了高效、安全和可维护的访问控制机制。
1.3、RBAC级别
RBAC0用户和角色是多对多角色和权限是多对多。一个用户拥有的权限是他所有角色的集合。RBAC1基于RBAC0并引入了角色分层的概念即一个角色分为多个等级每个等级对应的权限是不一样的。把权限分给用户时需要分到对应的角色等级。角色等级低时拥有的权限少角色等级高的权限是所有角色等级低的权限的集合。RBAC2基于RBAC1对角色访问进行限制。 如互斥角色限制同一个用户分配到两个角色且角色互斥时那么系统应该提醒只能选择其中一个角色。比如员工拥有商务这个角色可以创建结算单并提交给财务审核这时就不能赋予这个员工财务角色否则他就自己提交结算自己审核结算单了。角色数量限制一个用户拥有的角色数量是有限的一个角色被分配的用户数量也是有限的。先决条件限制用户想获得某个上级角色必须先获得其下一级的角色。比如想获得产品总监的权限那就需要从产品助理这一角色开始再到产品经理角色最后到产品总监角色。RBAC3基于RBAC0对RBAC1和RBAC2进行了整合是最全面的权限管理。
1.4、RBAC模型复杂情况
当用户非常多的情况可以设计用户组的概念用户组代替原先用户的概念这样能起到批量操作用户角色的作用
权限组的概念也差不多是权限过多的情况一个一个赋权操作太繁琐可以用权限组批量操作非常方便。 1.5、springSecruity中实际运用简单的步骤
用户表、角色表、权限表。然后两张关联表将用户和角色角色和权限做关联。添加用户的时候给user特定的用户角色。登录时将查询用户信息将角色信息放进token或缓存(比如redis外部缓存好处是能临时控制权限)中。登录后的操作都会经过自定义filter验证通过的话可以将用户信息放进springSecruity上下文和ThreadLocal这里是因为登录以及验证角色权限是单线程操作使用本地线程速度最快比map以及外部缓存都快。我们想使用权限而且无侵入的去控制的话可以弄个自定义注解参数为角色名验证ThreadLocal中保存的用户信息中的角色中是否包含此角色名返回boolean类型。
2、demo实现
结合前面我写的两篇帖子这里整理了一个demo能够实现一个简单的无侵入的登录及权限控制方案。这里用到springSecruity、jwt、redis、mysql、threadLocal等技术 0、springboot配置
数据源自己配就是要提前有redis和mysql
server:port: 8083spring:application:name: playerredis:host: xxxxxxxport: xxxxxxxdatasource:url: jdbc:mysql://xxxxxxx:xxxx/xxxxxxusername: rootpassword: Aa123456driver-class-name: com.mysql.cj.jdbc.Driverjpa:hibernate:ddl-auto: nonemybatis:mapper-locations: classpath:mappers/*.xmltype-aliases-package: com.loong.nba.player.pojo
1、依赖
dependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-security/artifactId/dependencydependencygroupIdio.jsonwebtoken/groupIdartifactIdjjwt-api/artifactIdversion0.11.2/version/dependencydependencygroupIdio.jsonwebtoken/groupIdartifactIdjjwt-impl/artifactIdversion0.11.2/versionscoperuntime/scope/dependencydependencygroupIdio.jsonwebtoken/groupIdartifactIdjjwt-jackson/artifactIdversion0.11.2/versionscoperuntime/scope/dependency!-- MyBatis --dependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactIdversion2.2.0/version/dependency!-- 数据库驱动 --dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion8.0.31/version/dependency
/dependencies
2、util
package com.loong.nba.player.util;import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;import java.security.Key;
import java.util.Date;
import java.util.concurrent.TimeUnit;/*** author jilong* date 2023/5/18*/
Component
public class JwtUtil {private final Key secretKey;private final long expirationTime;Autowiredprivate StringRedisTemplate redisTemplate;public JwtUtil() {this.secretKey Keys.secretKeyFor(SignatureAlgorithm.HS256);this.expirationTime 120000;}/*** 生成jwt令牌** param username 用户名* return token*/public String generateToken(String username) {Date now new Date();Date expirationDate new Date(System.currentTimeMillis() expirationTime);String token Jwts.builder().setSubject(username).setIssuedAt(now).setExpiration(expirationDate).signWith(secretKey, SignatureAlgorithm.HS256).compact();redisTemplate.opsForValue().set(username, token, expirationTime, TimeUnit.MILLISECONDS);return token;}/*** 解析令牌** param token token* return 内容*/public String getUsernameFormToken(String token) {return extractClaims(token).getBody().getSubject();}public boolean validateToken(String token) {try {JwsClaims claims extractClaims(token);return !claims.getBody().getExpiration().before(new Date());} catch (Exception e) {e.printStackTrace();return false;}}private JwsClaims extractClaims(String token) {JwtParser parser Jwts.parserBuilder().setSigningKey(secretKey).build();return parser.parseClaimsJws(token);}
}package com.loong.nba.player.util;import com.loong.nba.player.pojo.LoginUserBO;public class SessionUtils {static ThreadLocalLoginUserBO loginUser new ThreadLocal();public static LoginUserBO getLoginUser() {return loginUser.get();}public static void setLoginUser(LoginUserBO loginUserBO) {loginUser.set(loginUserBO);}
}3、pojo
package com.loong.nba.player.pojo;public class UserPO {private Integer id;private String username;private String password;private String salt;public Integer getId() {return id;}public void setId(Integer id) {this.id id;}public String getUsername() {return username;}public void setUsername(String username) {this.username username;}public String getPassword() {return password;}public void setPassword(String password) {this.password password;}public String getSalt() {return salt;}public void setSalt(String salt) {this.salt salt;}
}package com.loong.nba.player.pojo;import java.util.List;public class LoginUserBO {private String username;private Integer userId;private String password;private ListRole roleList;public String getUsername() {return username;}public void setUsername(String username) {this.username username;}public Integer getUserId() {return userId;}public void setUserId(Integer userId) {this.userId userId;}public String getPassword() {return password;}public void setPassword(String password) {this.password password;}public ListRole getRoleList() {return roleList;}public void setRoleList(ListRole roleList) {this.roleList roleList;}
}package com.loong.nba.player.pojo;public class Role {private Integer id;private String roleName;public Integer getId() {return id;}public void setId(Integer id) {this.id id;}public String getRoleName() {return roleName;}public void setRoleName(String roleName) {this.roleName roleName;}
}package com.loong.nba.player.pojo;/*** author jilong* date 2023/5/19*/
public class UserDO {private String name;private String password;public UserDO() {}public UserDO(String name, String password) {this.name name;this.password password;}public String getName() {return name;}public void setName(String name) {this.name name;}public String getPassword() {return password;}public void setPassword(String password) {this.password password;}
}4、config
package com.loong.nba.player.config;import com.loong.nba.player.filter.JwtAuthenticationFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;/*** author jilong* date 2023/5/18*/
Configuration
EnableWebSecurity
EnableGlobalMethodSecurity(prePostEnabled true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {private final JwtAuthenticationFilter jwtAuthenticationFilter;public SecurityConfig(JwtAuthenticationFilter jwtAuthenticationFilter) {this.jwtAuthenticationFilter jwtAuthenticationFilter;}Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers(/login,/user).permitAll().anyRequest().authenticated().and().addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class).sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);}Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}}5、dao层
package com.loong.nba.player.dao;import com.loong.nba.player.pojo.Role;
import org.apache.ibatis.annotations.Mapper;import java.util.List;Mapper
public interface RoleMapper {ListRole findByUserId(Integer id);}package com.loong.nba.player.dao;import com.loong.nba.player.pojo.UserPO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;Mapper
public interface UserMapper {UserPO findById(Integer id);UserPO findByName(Param(name) String name);Integer addUser(Param(userPO) UserPO userPO);}6、service
package com.loong.nba.player.service;import com.loong.nba.player.pojo.UserDO;
import com.loong.nba.player.pojo.UserPO;public interface UserService {/*** 添加用户* return 用户id*/UserPO addUser(UserDO userDO);boolean comparePassword(UserDO userDO);}package com.loong.nba.player.service;import com.loong.nba.player.dao.UserMapper;
import com.loong.nba.player.pojo.UserDO;
import com.loong.nba.player.pojo.UserPO;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;/*** author jilong* date 2023/5/19*/
Service
public class UserServiceImpl implements UserService {private final UserMapper userMapper;public UserServiceImpl(UserMapper userMapper) {this.userMapper userMapper;}Overridepublic UserPO addUser(UserDO userDO) {// 定义盐的长度字节数int saltLength 6;// 创建一个安全的随机数生成器SecureRandom secureRandom new SecureRandom();// 生成盐byte[] salt new byte[saltLength];secureRandom.nextBytes(salt);// 将盐转换为字符串或字节数组String saltString encodeSalt(salt);// 计算密码摘要String password encryptPassword(userDO.getPassword(), saltString);UserPO userPO new UserPO();userPO.setUsername(userDO.getName());userPO.setPassword(password);userPO.setSalt(saltString);userMapper.addUser(userPO);System.out.println(Salt (Base64 string): saltString);return userPO;}String encodeSalt(byte[] salt) {return Base64.getEncoder().encodeToString(salt);}byte[] decodeSaltString(String saltString) {return Base64.getDecoder().decode(saltString);}String encryptPassword(String password, String salt) {String plaintext password salt;try {// 创建SHA-256算法的MessageDigest实例MessageDigest digest MessageDigest.getInstance(SHA-256);// 计算中文字符串的摘要byte[] hash digest.digest(plaintext.getBytes(StandardCharsets.UTF_8));// 将摘要字节数组转换为十六进制字符串表示String digestHex bytesToHex(hash);System.out.println(SHA-256摘要 digestHex);return digestHex;} catch (NoSuchAlgorithmException e) {e.printStackTrace();}return null;}// 将摘要字节数组转换为十六进制字符串表示private static String bytesToHex(byte[] bytes) {StringBuilder hexStringBuilder new StringBuilder();for (byte b : bytes) {String hex Integer.toHexString(0xff b);if (hex.length() 1) {hexStringBuilder.append(0);}hexStringBuilder.append(hex);}return hexStringBuilder.toString();}Overridepublic boolean comparePassword(UserDO userDO) {UserPO user userMapper.findByName(userDO.getName());String salt user.getSalt();String password encryptPassword(userDO.getPassword(), salt);return password.equals(user.getPassword());}}7、filter
package com.loong.nba.player.filter;import com.loong.nba.player.dao.RoleMapper;
import com.loong.nba.player.dao.UserMapper;
import com.loong.nba.player.pojo.LoginUserBO;
import com.loong.nba.player.pojo.Role;
import com.loong.nba.player.pojo.UserPO;
import com.loong.nba.player.util.JwtUtil;
import com.loong.nba.player.util.SessionUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.filter.OncePerRequestFilter;import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.List;/*** author jilong* date 2023/5/18*/
Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {private final String tokenHeader Authorization;private final String tokenPrefix Bearer ;private final JwtUtil jwtUtil;private final StringRedisTemplate redisTemplate;private final UserMapper userMapper;private final RoleMapper roleMapper;public JwtAuthenticationFilter(JwtUtil jwtUtil, StringRedisTemplate redisTemplate, UserMapper userMapper, RoleMapper roleMapper) {this.jwtUtil jwtUtil;this.redisTemplate redisTemplate;this.userMapper userMapper;this.roleMapper roleMapper;}Overridepublic void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {String header request.getHeader(tokenHeader);if (!ObjectUtils.isEmpty(header) header.startsWith(tokenPrefix)) {String token header.replace(tokenPrefix, );if (!ObjectUtils.isEmpty(token) jwtUtil.validateToken(token)) {String username jwtUtil.getUsernameFormToken(token);UserPO userPO userMapper.findByName(username);ListRole roleList roleMapper.findByUserId(userPO.getId());LoginUserBO loginUserBO new LoginUserBO();loginUserBO.setUserId(userPO.getId());loginUserBO.setUsername(username);loginUserBO.setPassword(userPO.getPassword());loginUserBO.setRoleList(roleList);if (redisTemplate.opsForValue().get(username) ! null) {UsernamePasswordAuthenticationToken authenticationToken new UsernamePasswordAuthenticationToken(username, null, Collections.emptyList());SecurityContextHolder.getContext().setAuthentication(authenticationToken);SessionUtils.setLoginUser(loginUserBO);}}}chain.doFilter(request, response);}
}
8、controller
package com.loong.nba.player.controller;import com.loong.nba.player.pojo.UserDO;
import com.loong.nba.player.pojo.UserPO;
import com.loong.nba.player.service.UserServiceImpl;
import com.loong.nba.player.util.JwtUtil;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletResponse;/*** author jilong* date 2023/5/15*/
RestController
public class LoginController {private final JwtUtil jwtUtil;private final UserServiceImpl userService;public LoginController(JwtUtil jwtUtil, UserServiceImpl userService) {this.jwtUtil jwtUtil;this.userService userService;}PostMapping(/login)public ResponseEntityUserDO postLogin(RequestBody UserDO userDO, HttpServletResponse response) {if (!userService.comparePassword(userDO)) {return ResponseEntity.ok(new UserDO());}String token jwtUtil.generateToken(userDO.getName());response.addHeader(Authorization, Bearer token);return ResponseEntity.ok(userDO);}PostMapping(/user)public UserPO addUser(RequestBody UserDO userDO) {return userService.addUser(userDO);}GetMapping(/test)PreAuthorize(permission.hasRole(管理员))public String test() {return hello test;}
}9、mapper.xml
?xml version1.0 encodingUTF-8 ?
!DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtdmapper namespacecom.loong.nba.player.dao.RoleMapperselect idfindByUserId resultTypeRoleSELECT role.id , role.rolename FROM role where idIN (SELECT role_id FROM user_role WHERE user_id #{id})/select/mapper?xml version1.0 encodingUTF-8 ?
!DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtdmapper namespacecom.loong.nba.player.dao.UserMapperselect idfindById resultTypeUserPOSELECT * FROM user WHERE id #{id}/selectselect idfindByName resultTypeUserPOSELECT * FROM user WHERE username #{name}/selectinsert idaddUser parameterTypeUserPOINSERT INTO user (username, user_password, salt)VALUES (#{userPO.username}, #{userPO.password}, #{userPO.salt})/insert
/mapper