当前位置: 首页 > 工具软件 > RBAC Manager > 使用案例 >

Rbac-manager权限管理项目

乐正锦
2023-12-01

一、RBAC-MANAGER(用户权限管理)

1.pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.xgj</groupId>
    <artifactId>rbac-test-01</artifactId>
​
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
​
​
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.6</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.3.4</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.78</version>
        </dependency>
​
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
            <version>5.1.6</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
​
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
​
</project>
​

2.application.yml

server:
  port: 8082
  servlet:
    context-path: /rbac
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/incodedb
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
  jackson:
    date-format: yyyy-MM-dd
mybatis-plus:
  global-config:
    db-config:
      id-type: auto
      table-prefix: t_
logging:
  level:
    com.xgj.mapper: debug

Security

1.LoginUserDetailService

@Component
public class LoginUserDetailService implements UserDetailsService {
​
    @Autowired
    private UserService userService;
​
    @Autowired
    private AuthService authService;
​
    //用户登录的时候调用,根据用户输入的用户名去查询密码
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
​
        System.out.println("--------------------LoginUserDetailService-------------------------");
        System.out.println("用户【"+username+"】正在做登录操作。。。。");
        //1.根据用户名查询密码
       User user= userService.getUserByUsername(username);
​
       //2.判断用户是否存在
        if (user == null) {
                throw new RbacException(1001,"用户不存在");
        }
​
        //>查询当前用户的角色
        List<String> roleNameList=authService.getRoleListByUid(user.getId());
​
​
        //.3创建一个的登录的User对象
        SecurityUser securityUser=new SecurityUser();
        securityUser.setCurrentUser(user);
        securityUser.setRoleNameList(roleNameList);
​
​
    //4.返回SecurityUser,当时候SpringSecurity调用这个类中getPassword()来完成密码的比对
        return securityUser;
    }
}

2.JwtTokenFilter

​
@Component
public class JwtTokenFilter extends OncePerRequestFilter {
​
    @Autowired
    private LoginUserDetailService userDetailService;
​
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
​
        //1.获取Token
        String token = request.getHeader(SecurityConstant.TOKEN_NAME);
​
        //2.检验token
        Claims claim = JwtUtil.getClaim(token);
        if (claim == null) {
            Result error=Result.error();
            error.put("code",501);//501代表Token有误
            error.put("msg","没有携带token或token过期");
​
            ResponseUtil.out(response, error);
            return;
        }
        //3.token检验成功后从token中获取主体信息
        String username = claim.get(SecurityConstant.USER_NAME, String.class);
         List roleName= claim.get("roleName", List.class);
​
​
        //4.根据用户名查询用户信息
        SecurityUser securityUser = (SecurityUser) userDetailService.loadUserByUsername(username);
        List<String> roleNameList = securityUser.getRoleNameList();
​
        //5.封装
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(securityUser,null,securityUser.getAuthorities());
​
        //6.全局登录设置
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
​
        //7.放行
        filterChain.doFilter(request,response);
​
​
    }
}

3.UrlAuthenFilter

​
@Component
public class UrlAuthenFilter {
​
    @Autowired
    private PermissionService permissionService;
​
    @Autowired
    private AntPathMatcher antPathMatcher;
​
    @Autowired
    private AuthService authService;
​
    /**
    *@Author xiaogongjue
    *@Date2021/10/11 21:46
    *@Description request当前的请求  authentication主体
    */
    public boolean checkUrlAuthen(HttpServletRequest request, Authentication authentication){
​
        //1.定义一个标识,如果有权限为true
        boolean flag=false;
​
        //2.获取当前的请求
        String reqUrl = request.getRequestURL().toString();
​
        //3.获取Db中的全部URL
        List<Permission> dbUrlList = permissionService.allUrlList();
​
        //4.遍历dbUrllIst与当前的请求的Url----》urlId---->角色
​
        for (Permission permission : dbUrlList) {
​
            if(antPathMatcher.match(permission.getUrl(),reqUrl)){
                    //6.根据菜单id查询角色(访问这些url需要这些的角色)
              List<String> roleCodes= authService.getRoleCodeByPid(permission.getId());
​
              //7.判断当前主体是否有这写角色的一个
            SecurityUser securityUser= (SecurityUser) authentication.getPrincipal();
                List<String> userRoleNameList = securityUser.getRoleNameList();
                for (String roleCode : userRoleNameList) {
                        //如果是包含关系就是有权限
                    if(roleCodes.contains(roleCode)){
​
                        flag=true;
                    }
​
                }
​
            }
​
        }
        return flag;
    }
​

4.UserAccessDeniedHandler用户没有权限处理器

​
@Component
public class UserAccessDeniedHandler implements AccessDeniedHandler {
​
​
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
​
        Result error=Result.error();
        error.put("code",502);//502代表没有权限
        error.put("msg","你没有权限访问。。");
​
        ResponseUtil.out(httpServletResponse, error);
    }
}

5.UserAuthenticationEntryPoint用户没有登录(授权)

@Component
public class UserAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        ResponseUtil.out(httpServletResponse, Result.error("你还没有登录,请先登录"));
    }
}

6.UserLoginFilter用户登录的过滤器

​
@Component
public class UserLoginFilter extends UsernamePasswordAuthenticationFilter {
​
​
    @Autowired//从IOC容器注入authenticationManager给父类初始化
    @Override
    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
        super.setAuthenticationManager(authenticationManager);
    }
​
    //认证成功时调用
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        //1.当前登录的主体
        SecurityUser  securityUser = (SecurityUser) authResult.getPrincipal();
        System.out.println("欢迎:【"+securityUser+"】登录成功");
        //2.定义需要放入Token中的数据
        Map<String,Object> map=new HashMap<>();
        map.put(SecurityConstant.USER_NAME,securityUser.getUsername());
​
        map.put("roleName",securityUser.getRoleNameList());
​
        //3.创建Token
        String token = JwtUtil.createToken(map);
​
        //4.响应登录成功
​
        ResponseUtil.out(response,Result.putDate(SecurityConstant.TOKEN_NAME,token));
​
    }
    //认证失败后调用
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        ResponseUtil.out(response, Result.error("用户名或密码错误,请你重试~~"));
​
    }
}
​

mybatis-plus

1.UserMetaHandler(数据库自动填充)

/**
 * @Author xiaogongjue
 * @Date2021/10/6 12:56
 * @Description 自动填字段
 */
@Component
public class UserMetaHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        System.out.println("字段自动填充");
        Object status = getFieldValByName("status", metaObject);
        if (status == null) {
            setFieldValByName("status", 1, metaObject);
        }
        Object createTime = getFieldValByName("createTime", metaObject);
        if (createTime == null) {
            setFieldValByName("createTime", new Date(), metaObject);
        }
​
    }
​
    @Override
    public void updateFill(MetaObject metaObject) {
​
    }
}

2.common包下新建拣utils

工具类Result

public class Result extends HashMap<String, Object> {
​
    public Result() {
        //0代表成功,非0代表失败
        super.put("code", 0);
        super.put("msg", "success");
​
    }
​
    public static Result ok() {
        //响应成功
        return new Result();
    }
​
    //响应成功带有成功的提示信息
    public static Result ok(String msg) {
        Result r = new Result();
        r.put("msg", msg);
        return r;
    }
​
    //响应失败
    public static Result error() {
        Result r = new Result();
        r.put("code", 500);
        r.put("msg", "error");
        return r;
    }
​
    //响应失败带有失败的原因信息
    public static Result error(String msg) {
        Result r = Result.error();
        r.put("msg", msg);
        return r;
    }
​
    //对成功与否的判断
    public static Result out(Object value) {
​
        if (value instanceof Boolean) {//对操作结果是Boolean类型的操作,比例更新,删除
            if ((boolean) value) {
                return Result.ok();
            } else {
                return Result.error();
            }
​
        }else if(value instanceof Integer){//对操作结果是Integer类型的操作,比例插入
            if((Integer)value>0){
                return Result.ok();
​
            }else{
                return Result.error();
            }
​
        }
            return Result.error();
    }
    //将数据以键值对的形式存起来
    public static Result putDate(String key,Object object){
        Result r=new Result();
        r.put(key,object);
        return r;
    }
​
}
public class ResponseUtil {
​
    public static void out(HttpServletResponse response,Result r){
​
        //设置响应的数类型为JSON,编码格式为UTF-8
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding("utf-8");
​
        try {
            //将Result对象转成JSON字符串写出去
            response.getWriter().write(JSON.toJSONString(r));
        } catch (IOException e) {
            e.printStackTrace();
        }
​
    }
}
public class JwtUtil {
​
    private static final String sign = "2105-rbac"; // 签名
    private static final long EXPIRE = 1000 * 60 * 30; // 过期时间 30m
​
    /**
     * 生成token
     *
     * @return
     */
    public static String createToken(Map<String, Object> map) {
        Date nowDate = new Date();
        //过期时间
        Date expireDate = new Date(nowDate.getTime() + EXPIRE);
        return Jwts.builder()
                .setClaims(map) // 载荷
                .setIssuedAt(nowDate) // 当前时间
                .setExpiration(expireDate) // 过期时间
                .signWith(SignatureAlgorithm.HS512, sign) // 签名
                .compact();
    }
​
    /**
     * 解析Claims
     *
     * @param token
     * @return
     */
    public static Claims getClaim(String token) {
        Claims claims = null;
        try {
            claims = Jwts.parser()
                    .setSigningKey(sign)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            System.out.println("token解析失败");
        }
        return claims;
    }
​
    /**
     * 验证token是否失效
     *
     * @param token
     * @return true:过期   false:没过期
     */
    public static boolean isExpired(String token) {
        try {
            final Date expiration = getExpiration(token);
            return expiration.before(new Date());
        } catch (ExpiredJwtException expiredJwtException) {
            return true;
        }
    }
​
    /**
     * 获取jwt失效时间
     */
    public static Date getExpiration(String token) {
        return getClaim(token).getExpiration();
    }
}

config包下

/**
 * @Author xiaogongjue
 * @Date2021/10/11 11:31
 * @Description  跨越与拦截器
 */
@Component
public class CORSFilter implements Filter {
​
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
​
        HttpServletResponse response = (HttpServletResponse) servletResponse;
​
        response.setHeader("Access-Control-Allow-Origin", "*");
​
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, HEAD");
​
        response.setHeader("Access-Control-Max-Age", "3600");
​
        response.setHeader("Access-Control-Allow-Headers", "*");
​
        filterChain.doFilter(servletRequest,response);
​
    }
}
​
/**
 * @Author xiaogongjue
 * @Date2021/10/6 11:26
 * @Description 配置拦截器
 */
@Configuration
public class MPconfig {
​
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
     interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//将分页拦截器加入到MP配置中
​
            return interceptor;
    }
​
}
​
@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
​
    @Autowired
    private LoginUserDetailService loginUserDetailService;
​
    //给IOC容器中放入一个密码加密的算法
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    //认证过滤器
    @Autowired
    private UserLoginFilter userLoginFilter;
    //没有权限处理器
    @Autowired
    private UserAccessDeniedHandler userAccessDeniedHandler;
    //没有登录(认证)处理器
    @Autowired
    private UserAuthenticationEntryPoint userAuthenticationEntryPoint;
​
    @Autowired
    private JwtTokenFilter jwtTokenFilter;
​
​
    // 复写父类中的 AuthenticationManager 添加IOC容器中
    @Bean
    @Override
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }
​
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .userDetailsService(loginUserDetailService) // 设置userDetails
                .passwordEncoder(passwordEncoder()); // 设置加密算法
    }
​
    @Override
    protected void configure(HttpSecurity http) throws Exception {
       http.addFilter(userLoginFilter)
               //jwtTokenFilter要在BasicAuthenticationFilter之前运行
               .addFilterBefore(jwtTokenFilter, BasicAuthenticationFilter.class)
               .exceptionHandling().accessDeniedHandler(userAccessDeniedHandler)//没有权限处理器
               .authenticationEntryPoint(userAuthenticationEntryPoint)//没有认证的处理器
                //.and().authorizeRequests().anyRequest().authenticated()//所有资源度需要认证后才能访问
                //声明用Token登录
          .and().authorizeRequests().anyRequest().access("@urlAuthenFilter.checkUrlAuthen(request,authentication)")
​
               .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
       .and().csrf().disable()
               ;
    }
}
​
​
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
​
//    @Override
//    public void addCorsMappings(CorsRegistry registry) {
//        registry.
//                addMapping("/**")
//                .allowedMethods("POST","GET","DELETE","PUT")
//                .allowedHeaders("*")
//                .allowedOrigins("*");
//
//
//    }
​
    @Autowired
    private CORSFilter corsFilter;
​
    @Bean
    public AntPathMatcher antPathMatcher(){
        return new AntPathMatcher();
    }
​
    @Bean
    public FilterRegistrationBean testFilterRegistration() {
​
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(corsFilter);
        registration.addUrlPatterns("/*");
        registration.setName("corsFilter");
        registration.setOrder(Integer.MIN_VALUE);
        return registration;
    }
}

entity(权限实体)

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Permission implements Serializable {
   @TableId
    private Integer id;
    private String name;
    private String url;
    private Integer type;
    private Integer status;
    private Integer pid;//父ID
    @TableField(exist = false)
    private String pname;//告诉MP表中不存在这个字段
}
​

权限controller

@RestController
@RequestMapping("/per/")
public class PermissionController {
​
    @Autowired
    private PermissionService permissionService;
​
    @PostMapping("save")
    public Result savePer(@RequestBody Permission permission){
        boolean save = permissionService.save(permission);
        return Result.out(save);
​
    }
​
    @GetMapping("/treeList")
    public Result treeList(){//后端返回的是简单的JSON数据
     return Result.putDate("data", permissionService.treeList());
​
    }
​
    @PostMapping("page")
    public Result pagePer(@RequestBody Page<Permission> permissionPage){
        Page<Permission> page = permissionService.page(permissionPage);
        return Result.putDate("page",page);
    }
    @GetMapping("delete/{id}")
    public Result deletePer(@PathVariable Integer id){
      return Result.out(permissionService.removeById(id));
​
    }
    @PostMapping("update")
    public Result updatePer(@RequestBody Permission permission){
       return Result.out(permissionService.updateById(permission));
    }
    @GetMapping("getById/{id}")
    public Result getPerById(@PathVariable Integer id){
        Permission permission = permissionService.getAllById(id);
        return Result.putDate("permission",permission);
    }
}

PermissionMapper

public interface PermissionMapper extends BaseMapper<Permission> {
    List<Permission> treeList();
​
    Permission getAllById(Integer id);
​
    List<Permission> allUrlList();
​
}

PermissionService

public interface PermissionService extends IService<Permission> {
    List<Permission> treeList();
​
    Permission getAllById(Integer id);
​
    List<Permission> allUrlList();
​
​
}

在resource下新建一个mapper目录,存放PermissionMapper.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
​
<mapper namespace="com.xgj.mapper.PermissionMapper">
​
   <select id="getAllById" resultType="com.xgj.entity.Permission">
SELECT t1.*,t2.`name` AS pname FROM t_permission t1 LEFT JOIN t_permission t2 ON t1.`pid`=t2.`id` WHERE t1.id=#{id}
</select>
​
    <select id="treeList" resultType="com.xgj.entity.Permission">
SELECT t1.*,t2.`name` as pname from t_permission t1 LEFT JOIN t_permission t2 ON (t1.pid=t2.id)
</select>
​
<select id="allUrlList" resultType="com.xgj.entity.Permission">
​
SELECT * FROM t_permission p WHERE LENGTH(p.url)>0
​
</select>
​
</mapper>
 类似资料: