SpringBoot+SpringSecurity系列八:整合JWT #yyds干货盘点#
Posted 梁云亮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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");
相关代码
@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;
以上是关于SpringBoot+SpringSecurity系列八:整合JWT #yyds干货盘点#的主要内容,如果未能解决你的问题,请参考以下文章
Java 之SpringBoot+SpringSecurity+Vue实现后台管理系统的开发三系统权限
使用篇二SpringBoot集成SpringSecurity(22)
SpringBoot集成SpringSecurity+CAS