赞
踩
在第3步中,需要做一个登录验证成功时的拦截,拦截后生成JwtToken然后写入到响应内容里面,这样前端就能接收到通过/login请求获取到的JwtToken数据。于此同时,也需要将拦截时获取到的authentication写入到SecurityContextHolder中,为下次前端通过JwtToken验证做准备。
在第4步中,通过增加JwtFilter过滤器来验证身份,允许前端通过携带正确且未过期的JwtToken进行身份验证,验证时需要同样需要通过LoadUserByUsername方法获取UserDetails对象(Principal对象),然后创建一个UsernamePasswordAuthenticationToken对象给SecurityContextHolder验证,如果和步骤2中写入的authentication一致,即验证成功,正确获取到用户权限。
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.0.0</version>
</dependency>
JwtToken工具类的核心功能包括创建token和验证token
package com.example.demo.utils.jwt; /** * @Author : HuangJiajian * @create 2022/9/28 10:29 */ public class JwtUtils { private static final String secret = "test123456"; /** * @Author HJJ * @Date 2022-12-28 16:59 * @Params userId,userName * @Return token * @Description 创建Token,默认时间为7天 */ public static String createToken(String userName, String authentications){ long expire = 7 * 24 * 3600 * 1000; return JWT.create().withAudience(userName) .withIssuedAt(new Date()) .withExpiresAt(new Date(System.currentTimeMillis()+ expire)) .withClaim("authentications", authentications) .sign(Algorithm.HMAC256(userName+secret)); } /** * @Author HJJ * @Date 2022-12-28 16:59 * @Params token, userName * @Return boolean * @Description 验证Token,过期或不正确时会返回false */ public static boolean verifyToken(String token, String userName){ DecodedJWT jwt = null; try { JWTVerifier verifier = JWT.require(Algorithm.HMAC256(userName+secret)).build(); jwt = verifier.verify(token); return true; } catch (Exception e) { System.out.println(e); } return false; } }
在SecurityConfig文件中配置登录验证成功时的拦截器,详细配置可见另一篇文章
package com.example.demo.config.security; @Configuration public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { // 登录 httpSecurity.formLogin() .loginProcessingUrl("/login") .loginPage("/login.html") .successHandler(new AuthenticationSuccessConfig()) .failureHandler(new AuthenticationFailConfig()); } }
自定义AuthenticationSuccessConfig
登录成功拦截,重点需要关注将authentication写入SecurityContextHolder的步骤和将JwtToken写入response的步骤
package com.example.demo.config.security; /** * @Author : HuangJiajian * @create 2022/10/20 16:24 */ public class AuthenticationSuccessConfig implements AuthenticationSuccessHandler { /** * @Author HJJ * @Date 2022-12-28 17:20 * @Params * @Return * @Description 整合JWT,在身份验证成功时,生成JwtToken并将authentication写入SpringSecurity中 */ @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { UsernamePasswordAuthenticationToken user = (UsernamePasswordAuthenticationToken) authentication; String token = JwtUtils.createToken(user.getName(), user.getAuthorities().toString()); SecurityContextHolder.getContext().setAuthentication(authentication); response.setContentType("text/json;charset=utf-8"); PrintWriter writer = response.getWriter(); writer.write(JSON.toJSONString(new AjaxResult(AjaxResult.CODE.SUCCESS, "success", token))); writer.flush(); writer.close(); } }
在SecurityConfig文件中配置Filter,详细配置可见另一篇文章
package com.example.demo.config.security;
@Configuration
public class SecurityConfig {
@Autowired
private JwtFilter jwtFilter;
@Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
}
}
自定义JwtFilter拦截器,
package com.example.demo.config.security; /** * @Author : HuangJiajian * @create 2022/12/29 9:14 */ @Component public class JwtFilter extends OncePerRequestFilter { @Autowired private UserDetailServiceImpl userDetailsService; /** * @Author HJJ * @Date 2022-12-29 9:18 * @Params * @Return * @Description 获取请求中携带的JwtToken信息,并验证其真实性 */ @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String token = ""; String username = ""; for (Cookie cookie : request.getCookies()) { if (cookie.getName().equals("username")) { username = cookie.getValue(); } if (cookie.getName().equals("token")) { token = cookie.getValue(); } } if (token.isEmpty() || username.isEmpty()){ filterChain.doFilter(request, response); return; } UserDetails userDetails = userDetailsService.loadUserByUsername(username); if (JwtUtils.verifyToken(token, username)) { // 验证成功后,将authentication与在第一次登录时写入的权限做对比,如果成功即可跳过原本的验证了 UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authentication); } else { System.out.println(username + "JwtToken验证失败"); } filterChain.doFilter(request, response); } }
以上就是SpringSecurity整合JwtToken的全过程。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。