SpringBoot+SpringSecurity系列八(整合JWT#yyds干货盘点#)

历览千载书,时时见遗烈。这篇文章主要讲述SpringBoot+SpringSecurity系列八:整合JWT#yyds干货盘点#相关的知识,希望能为你提供帮助。
数据库:

SpringBoot+SpringSecurity系列八(整合JWT#yyds干货盘点#)

文章图片

第一步:当用户在没有授权时返回的指定信息的Handler
@Slf4j @Component public class JwtAccessDeniedHandler implements AccessDeniedHandler @Override public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws ServletException log.info("用户访问没有授权资源:", e.getMessage()); response.setContentType("application/json; charset=utf-8"); response.setCharacterEncoding("utf-8"); try (PrintWriter out = response.getWriter(); ) Result result = ResultUtil.fail("用户访问未授权资源").setCode(HttpServletResponse.SC_UNAUTHORIZED); out.write(JsonUtil.obj2String(result)); out.flush(); catch (IOException exception) log.error(e.getMessage()); e.printStackTrace();

第二步:访问受限资源时未登录或未携带正确token时返回信息的EntryPoint
@Slf4j @Component public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws ServletException, IOException log.info("登录失败or用户访问资源没有携带正确的token:", e.getMessage()); response.setContentType("application/json; charset=utf-8"); response.setCharacterEncoding("utf-8"); try (PrintWriter out = response.getWriter(); ) Result result = ResultUtil.fail("用户访问资源没有携带正确的token").setCode(HttpServletResponse.SC_UNAUTHORIZED); out.write(JsonUtil.obj2String(result)); out.flush(); catch (IOException exception) log.error(e.getMessage()); e.printStackTrace();

第三步:定义JWT认证过滤器
@Slf4j @Component public class JwtAuthenticationFilter extends OncePerRequestFilter @Resource private JwtUtil jwtUtil; @Resource private UserDetailsServiceImpl userDetailsService; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException String token = request.getHeader(jwtUtil.getHeader()); log.info("header token:", token); //如果请求头中有token,则进行解析,并且设置认证信息 if (token != null & & token.trim().length() > 0) //根据token获取用户名 String username = jwtUtil.getSubjectFromToken(token); // 验证username,如果验证合法则保存到SecurityContextHolder if (username != null & & SecurityContextHolder.getContext().getAuthentication() == null) UserDetails userDetails = userDetailsService.loadUserByUsername(username); // JWT验证通过,使用Spring Security 管理 if (jwtUtil.validateToken(token, userDetails)) //加载用户、角色、权限信息 UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, null, userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authentication); //如果请求头中没有Authorization信息则直接放行 chain.doFilter(request, response);

第四步:自定义UserDetailsService
@Service public class UserDetailsServiceImpl implements UserDetailsService @Resource private UserService userService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException MenuItemAuth menuItemAuth = userService.getAuthoritiesPermissions(username); System.out.println(JsonUtil.obj2String(menuItemAuth)); UserDetails userDetails = org.springframework.security.core.userdetails.User.withUsername(username) .password(menuItemAuth.getPassword()) .authorities(menuItemAuth.getAuth().split(",")) .build(); //UserDetails userDetails = new org.springframework.security.core.userdetails.User(username, passwordEncoder.encode("1234"), //AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_vip,user:list,user:update")); return userDetails;

相关的代码如下所示:
  • MenuItem.java
    @Getter @Setter @Builder @ToString @AllArgsConstructor @NoArgsConstructor public class MenuItem /** * 编号 */ private Integer id; /** * 名称 */ private String name; /** * 权限名称 */ private String code; /** * 父编号 */ private Integer pid;

  • MenuItemAuth.java
    @Getter @Setter @ToString @Builder @AllArgsConstructor @NoArgsConstructor public class MenuItemAuth /** * 后台管理系统菜单项列表 */ List< MenuItem> menuItemList; /** * 用户的密码 */ private String password; /** * 用户角色code+权限code的字符串 */ private String auth;

第五步:定义SpringSecurity配置类
@Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) public class SpringSecurityJwtConfig extends WebSecurityConfigurerAdapter @Bean public PasswordEncoder passwordEncoder() return new BCryptPasswordEncoder(); @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception return super.authenticationManagerBean(); @Resource private JwtAccessDeniedHandler jwtAccessDeniedHandler; @Resource private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; @Resource private JwtAuthenticationFilter jwtAuthenticationFilter; @Override protected void configure(HttpSecurity http) throws Exception http.csrf().disable(); // 禁用session http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); http.authorizeRequests() //login 不拦截 .antMatchers("/user/login").permitAll() .antMatchers("/user/login0").permitAll() .antMatchers("/init/redis").permitAll() .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() .antMatchers("/").permitAll() .anyRequest().authenticated(); //用户访问没有授权资源 http.exceptionHandling().accessDeniedHandler(jwtAccessDeniedHandler); //授权错误信息处理 //用户访问资源没有携带正确的token http.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint); // 使用自己定义的拦截机制验证请求是否正确,拦截jwt http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

Controller
@RestController @RequestMapping("/authority") public class AuthorityController @PostMapping("/login") public Result login(@RequestBody User user) // 登陆验证 UsernamePasswordAuthenticationToken token0 = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword()); Authentication authentication = authenticationManager.authenticate(token0); SecurityContextHolder.getContext().setAuthentication(authentication); //生成token,返回给客户端 MenuItemAuth menuItemAuth = userService.getAuthoritiesPermissions(user.getUsername()); UserDetails userDetails = org.springframework.security.core.userdetails.User.withUsername(user.getUsername()) .password(menuItemAuth.getPassword()) .authorities(menuItemAuth.getAuth().split(",")) .build(); String token = jwtUtil.generateToken(userDetails, user1.getId() + ""); return ResultUtil.success().setData("token", token); @GetMapping("/fun1") @PreAuthorize("hasRole(\\"vip\\")") public Result fun1() return ResultUtil.success("fun1"); @GetMapping("/fun2") @PreAuthorize("hasRole(\\"admin\\")") public Result fun2() return ResultUtil.success("fun2"); @GetMapping("/fun3") @PreAuthorize("hasAuthority(\\"user:list\\")") public Result fun3() return ResultUtil.success("fun3"); @GetMapping("/fun4") @PreAuthorize("hasAuthority(\\"user:delete\\")") public Result fun4() return ResultUtil.success("fun4");

【SpringBoot+SpringSecurity系列八(整合JWT#yyds干货盘点#)】相关代码
@Service @CacheConfig(cacheManager = "cacheManager") public class UserServiceImpl extends ServiceImpl< UserMapper, User> implements UserService @Resource RedisService< User> userRedisServiceImpl; @Resource private RoleService roleService; @Resource private UserPermissionService userPermissionService; @Resource private PermissionService permissionService; @Resource private RolePermissionService rolePermissionService; @Override public MenuItemAuth getAuthoritiesPermissions(String username) List< MenuItem> menuItemList = new ArrayList< > (); //根据用户名查找用户 User user = baseMapper.selectOne(new QueryWrapper< User> () .select("id", "username", "password", "nickname", "email", "tel", "gender", "birth", "avatar", "role_id") .eq("username", username) .eq("status", BaseStatus.Status.ok)); //查找角色 Role role = roleService.getOne(new QueryWrapper< Role> () .select("id", "name", "code") .eq("status", BaseStatus.Status.ok) .eq("id", user.getRoleId())); menuItemList.add(MenuItem.builder() .id(role.getId()) .name(role.getName()) .code(role.getCode()) .pid(-1) // -1表示是角色 .build()); String authorities = "ROLE_" + role.getCode() + ","; // 当前用户拥有的权限permission的id的集合 List< Integer> permissionIdList = new ArrayList< > (); //在tb_role_permission中查找Role所对应的角色 List< RolePermission> rolePermissionList = rolePermissionService.list(new QueryWrapper< RolePermission> () .select("permission_id") .eq("role_id", role.getId()) .eq("status", BaseStatus.Status.ok)); List< Integer> pid1 = rolePermissionList.stream().map(item -> item.getPermissionId()).collect(Collectors.toList()); permissionIdList.addAll(pid1); //在tb_user_permission中查找权限 List< UserPermission> userPermissionList = userPermissionService.list(new QueryWrapper< UserPermission> () .select("permission_id") .eq("user_id", user.getId()) .eq("status", BaseStatus.Status.ok)); List< Integer> pid2 = userPermissionList.stream().map(item -> item.getPermissionId()).collect(Collectors.toList()); permissionIdList.addAll(pid2); //查找具体的权限信息 List< Permission> permissionList = permissionService.list(new QueryWrapper< Permission> () .select("id", "name", "code", "pid") .eq("status", BaseStatus.Status.ok) .in("id", permissionIdList)); List< MenuItem> permissionMenuItemList = permissionList.stream().map(item -> MenuItem.builder() .id(item.getId()) .name(item.getName()) .code(item.getCode()) .pid(item.getPid()) .build()).collect(Collectors.toList()); menuItemList.addAll(permissionMenuItemList); String permissions = permissionList.stream().map(item -> item.getCode() + ",").collect(Collectors.joining()); System.out.println(permissions); //去掉最后一个逗号 permissions = permissions.substring(0, permissions.length() - 1); System.out.println(authorities + permissions); MenuItemAuth res = MenuItemAuth.builder() .menuItemList(menuItemList) .auth(authorities + permissions) .password(user.getPassword()) .build(); return res;


    推荐阅读