一、前言
本篇文章将报告Spring Security 简单整合JWT 处理认证授权
根本环境
- spring-boot 2.1.8
- mybatis-plus 2.2.0
- mysql 数据库
- maven项目
Spring Security入门学习可参考之前文章:
- SpringBoot集成Spring Security入门体验(一)
https://blog.csdn.net/qq_38225558/article/details/101754743
- Spring Security 自定义登录认证(二)
https://blog.csdn.net/qq_38225558/article/details/102542072
- Spring Security 动态url权限控制(三)
https://blog.csdn.net/qq_38225558/article/details/102637637
二、 Spring Security 简单整合 JWT
有关JWT 不了解的可以看下官网文档:https://jwt.io/introduction/
1、引入jwt依赖- <code> <!-- jwt依赖: https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
- <dependency>
- <groupId>io.jsonwebtoken</groupId>
- <artifactId>jjwt</artifactId>
- <version>0.9.1</version>
- </dependency></code>
复制代码2、在Security登录认证乐成后生成jwt令牌返回给前端生存
jwt生成令牌代码如下: - <code>// 生成jwt访问令牌
- String jwtToken = Jwts.builder()
- // 用户脚色
- .claim("ROLE_LOGIN", "ADMIN")
- // 主题 - 存用户名
- .setSubject("张三")
- // 逾期时间 - 30分钟
- .setExpiration(new Date(System.currentTimeMillis() + 30 * 60 * 1000))
- // 加密算法和密钥
- .signWith(SignatureAlgorithm.HS512, "helloworld")
- .compact();</code>
复制代码这里贴出小编文末案例demo源码中关于登录认证处理中的使用 - <code>@Component
- public class AdminAuthenticationProvider implements AuthenticationProvider {
- @Autowired
- UserDetailsServiceImpl userDetailsService;
- @Autowired
- private UserMapper userMapper;
- @Override
- public Authentication authenticate(Authentication authentication) throws AuthenticationException {
- // 获取前端表单中输入后返回的用户名、密码
- String userName = (String) authentication.getPrincipal();
- String password = (String) authentication.getCredentials();
- SecurityUser userInfo = (SecurityUser) userDetailsService.loadUserByUsername(userName);
- boolean isValid = PasswordUtils.isValidPassword(password, userInfo.getPassword(), userInfo.getCurrentUserInfo().getSalt());
- // 验证密码
- if (!isValid) {
- throw new BadCredentialsException("密码错误!");
- }
- // 前后端分离环境下 处理逻辑...
- // 更新登录令牌
- // 当前用户所拥有脚色代码
- String roleCodes = userInfo.getRoleCodes();
- // 生成jwt访问令牌
- String jwt = Jwts.builder()
- // 用户脚色
- .claim(Constants.ROLE_LOGIN, roleCodes)
- // 主题 - 存用户名
- .setSubject(authentication.getName())
- // 逾期时间 - 30分钟
- .setExpiration(new Date(System.currentTimeMillis() + 30 * 60 * 1000))
- // 加密算法和密钥
- .signWith(SignatureAlgorithm.HS512, Constants.SALT)
- .compact();
- User user = userMapper.selectById(userInfo.getCurrentUserInfo().getId());
- user.setToken(jwt);
- userMapper.updateById(user);
- userInfo.getCurrentUserInfo().setToken(jwt);
- return new UsernamePasswordAuthenticationToken(userInfo, password, userInfo.getAuthorities());
- }
- @Override
- public boolean supports(Class<?> aClass) {
- return true;
- }
- }</code>
复制代码前端页面生存的jwt令牌格式如下:
3、Security访问鉴权中认证用户信息
我们在访问每一个url请求的时间,在同一认证的地方获取jwt中我们必要的信息然后认证即可,【注: Claims 中存放着我们必要的信息】
比方: 我们可以将用户名、密码存放jwt中,然后在认证的时间读取到此中的用户信息,然后查询数据库认证用户,假如满意条件即乐成访问,假如不满意条件即抛出非常处理
温馨小提示:假如jwt令牌逾期,会抛出ExpiredJwtException 非常,我们必要拦截到,然后交给认证失败处理器中处理,然后返回给前端,这里根据个人业务实际处理即可~
- <code>// 获取jwt中的信息
- Claims claims = Jwts.parser().setSigningKey("helloworld").parseClaimsJws(jwtToken.replace("Bearer", "")).getBody();
- // 获取当前登录用户名
- System.out.println("获取当前登录用户名: " + claims.getSubject());</code>
复制代码小编项目中认证过滤器中的使用如下: - <code>@Slf4j
- @Component
- public class MyAuthenticationFilter extends OncePerRequestFilter {
- @Autowired
- AdminAuthenticationEntryPoint authenticationEntryPoint;
- private final UserDetailsServiceImpl userDetailsService;
- protected MyAuthenticationFilter(UserDetailsServiceImpl userDetailsService) {
- this.userDetailsService = userDetailsService;
- }
- @Override
- protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
- MultiReadHttpServletRequest wrappedRequest = new MultiReadHttpServletRequest(request);
- MultiReadHttpServletResponse wrappedResponse = new MultiReadHttpServletResponse(response);
- StopWatch stopWatch = new StopWatch();
- try {
- stopWatch.start();
- // 前后端分离环境下,前端登录后将token储存在cookie中,每次访问接口时通过token去拿用户权限
- String jwtToken = wrappedRequest.getHeader(Constants.REQUEST_HEADER);
- log.debug("背景查抄令牌:{}", jwtToken);
- if (StringUtils.isNotBlank(jwtToken)) {
- // JWT干系start ===========================================
- // 获取jwt中的信息
- Claims claims = Jwts.parser().setSigningKey(Constants.SALT).parseClaimsJws(jwtToken.replace("Bearer", "")).getBody();
- // 获取当前登录用户名
- System.out.println("获取当前登录用户名: " + claims.getSubject());
- // TODO 如需使用jwt特性在此做处理~
- // JWT干系end ===========================================
- // 查抄token
- SecurityUser securityUser = userDetailsService.getUserByToken(jwtToken);
- if (securityUser == null || securityUser.getCurrentUserInfo() == null) {
- throw new BadCredentialsException("TOKEN已逾期,请重新登录!");
- }
- UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(securityUser, null, securityUser.getAuthorities());
- // 全局注入脚色权限信息和登录用户根本信息
- SecurityContextHolder.getContext().setAuthentication(authentication);
- }
- filterChain.doFilter(wrappedRequest, wrappedResponse);
- } catch (ExpiredJwtException e) {
- // jwt令牌逾期
- SecurityContextHolder.clearContext();
- this.authenticationEntryPoint.commence(wrappedRequest, response, null);
- } catch (AuthenticationException e) {
- SecurityContextHolder.clearContext();
- this.authenticationEntryPoint.commence(wrappedRequest, response, e);
- } finally {
- stopWatch.stop();
- }
- }
- }</code>
复制代码简单的入门使用就是这样了
三、总结
- 引入
jwt依赖
- 登录体系乐成后
生成jwt令牌 返回给前端生存到欣赏器请求头 中
- 在每一次请求访问体系url时,在同一认证过滤器中获取到请求头中jwt令牌中生存的
用户信息 然后做认证处理 ,假如满意条件乐成访问,假如不满意交给认证失败处理器返回指定内容给前端
本文案例demo源码
https://gitee.com/zhengqingya/java-workspace
来源:https://www.cnblogs.com/zhengqing/p/11726855.html |