标签:return token private class Rbac manager Result 权限 public
一、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>
标签:return,token,private,class,Rbac,manager,Result,权限,public 来源: https://blog.csdn.net/weixin_43562801/article/details/120774126
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。