博客
关于我
Day243.JWT结合SpringSecurity -springsecurity-jwt-oauth2
阅读量:319 次
发布时间:2019-03-04

本文共 5094 字,大约阅读时间需要 16 分钟。

JWT与Spring Security认证鉴权详述

基于Session的应用开发缺陷

传统的B/S应用开发采用Session进行状态管理,通过cookie和sessionid实现用户状态的存取。这种方式在非浏览器客户端和集群应用中存在诸多问题,如无法自动维护cookie,且session不可共享。

JWT是什么

JWT(JSON Web Token)是一种用于传输用户身份信息的加密令牌,广泛应用于无状态的前后端分离应用开发。通过JWT,客户端无需存储任何状态信息,服务端仅需解签验证令牌即可获取用户信息。

JWT结构分析

JWT由三部分组成:Header(头)、Payload(有效载荷)和Signature(签名)。Header包含算法信息,Payload携带用户标识和其他自定义信息,Signature用于防止数据篡改。

JWT安全性

JWT的安全性依赖于密钥的保密性。通过HTTPS传输和定期更换密钥,可以有效提升JWT的安全性。服务端需妥善保护密钥,防止泄露。

Spring Security与JWT结合

认证流程

客户端通过用户名密码申请JWT,服务端验证后生成令牌并返回。Spring Security通过AuthenticationManager进行认证,生成JWT后返回给客户端。

接口鉴权

客户端将JWT放在HTTP请求头中,服务端通过 JwtRequestFilter 拦截请求,解签验证令牌,结合UserDetailsService获取用户信息,完成接口权限校验。

JWT工具类实现

开发JwtTokenUtil类,用于生成、解签、刷新JWT令牌。类似代码示例如下:

import io.jsonwebtoken.Claims;import io.jsonwebtoken.Jwts;import io.jsonwebtoken.SignatureAlgorithm;import org.springframework.security.core.userdetails.UserDetails;import java.util.Map;import java.util.Date;@Data@Componentpublic class JwtTokenUtil {    private String secret;    private Long expiration;    private String header;    public String generateToken(UserDetails userDetails) {        Map
claims = new HashMap<>(); claims.put("sub", userDetails.getUsername()); claims.put("created", new Date()); return generateToken(claims); } public String getUsernameFromToken(String token) { Claims claims = getClaimsFromToken(token); return claims.getSubject(); } public Boolean isTokenExpired(String token) { Claims claims = getClaimsFromToken(token); return claims.getExpiration().before(new Date()); } public String refreshToken(String oldToken) { Claims claims = getClaimsFromToken(oldToken); claims.put("created", new Date()); return generateToken(claims); } public Boolean validateToken(String token, UserDetails userDetails) { String username = getUsernameFromToken(token); return username.equals(userDetails.getUsername()) && !isTokenExpired(token); } private String generateToken(Map
claims) { Date expirationDate = new Date(System.currentTimeMillis() + expiration); return Jwts.builder() .setClaims(claims) .setExpirationDate(expirationDate) .signWith(SignatureAlgorithm.HS512, secret) .compact(); } private Claims getClaimsFromToken(String token) { Claims claims = null; try { claims = Jwts.parser() .setSigningKey(secret) .parseClaimsJws(token) .getBody(); } catch (Exception e) { claims = null; } return claims; }}

登录接口实现

定义JwtAuthController类,实现登录和令牌刷新接口。代码示例如下:

@RestControllerpublic class JwtAuthController {    @Resource    private JwtAuthService jwtAuthService;    @PostMapping("/authentication")    public AjaxResponse login(@RequestBody Map
map) { String username = map.get("username"); String password = map.get("password"); if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) { return AjaxResponse.error(new CustomException( CustomExceptionType.USER_INPUT_ERROR, "用户名密码不能为空")); } try { return AjaxResponse.success(jwtAuthService.login(username, password)); } catch (CustomException e) { return AjaxResponse.error(e); } } @PostMapping("/refreshtoken") public AjaxResponse refresh(@RequestHeader("${jwt.header}") String token) { return AjaxResponse.success(jwtAuthService.refreshToken(token)); }}

接口鉴权过滤器

自定义JwtAuthenticationTokenFilter类,拦截请求解析JWT,校验用户权限,并通过Spring Security进行接口权限控制。代码示例如下:

@Componentpublic class JwtAuthenticationTokenFilter extends OncePerRequestFilter {    @Resource    private JwtTokenUtil jwtTokenUtil;    @Override    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)            throws ServletException, IOException {        String jwtToken = request.getHeader(jwtTokenUtil.getHeader());        if (jwtToken != null && !StringUtils.isEmpty(jwtToken)) {            String username = jwtTokenUtil.getUsernameFromToken(jwtToken);            if (username != null &&                    SecurityContextHolder.getContext().getAuthentication() == null) {                UserDetails userDetails = jwtTokenUtil.myUserDetailsService.loadUserByUsername(username);                if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {                    UsernamePasswordAuthenticationToken authenticationToken =                            new UsernamePasswordAuthenticationToken(userDetails, null,                                    userDetails.getAuthorities());                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);                }            }        }        filterChain.doFilter(request, response);    }}

测试与常见问题

通过Postman测试登录接口获取JWT,测试成功后将令牌添加至HTTP请求头,访问受保护接口。确保权限配置正确,否则可能出现权限不足问题。

总结

JWT在无状态应用中提供了高效的身份验证方案,结合Spring Security,可实现细粒度的权限控制。虽然面临密钥保密等挑战,但通过合理配置和定期更新,可有效保障安全性。

转载地址:http://bpoq.baihongyu.com/

你可能感兴趣的文章
Objective-C实现双向A*算法(附完整源码)
查看>>
Objective-C实现双向广度优先搜索算法(附完整源码)
查看>>
Objective-C实现双向循环链表(附完整源码)
查看>>
Objective-C实现双向链表(附完整源码)
查看>>
Objective-C实现双端队列算法(附完整源码)
查看>>
Objective-C实现双线性插值(附完整源码)
查看>>
Objective-C实现双重链表(附完整源码)
查看>>
Objective-C实现反向传播神经网络算法(附完整源码)
查看>>
Objective-C实现反转位算法(附完整源码)
查看>>
Objective-C实现反转字符串算法(附完整源码)
查看>>
Objective-C实现合并两棵二叉树算法(附完整源码)
查看>>
Objective-C实现后缀表达式(附完整源码)
查看>>
Objective-C实现向量叉乘(附完整源码)
查看>>
Objective-C实现哈希查找(附完整源码)
查看>>
Objective-C实现哈希表算法(附完整源码)
查看>>
Objective-C实现哥德巴赫猜想(附完整源码)
查看>>
Objective-C实现唯一路径问题的动态编程方法的算法(附完整源码)
查看>>
Objective-C实现唯一路径问题的回溯方法的算法(附完整源码)
查看>>
Objective-C实现四舍五入(附完整源码)
查看>>
Objective-C实现四阶龙格库塔法(附完整源码)
查看>>