SpringSecurity+JWT登录时遇见的问题
package com.bai.server.config.security;
import io.jsonwebtoken.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* @author bai
* @date 2023年02月19日 16:25
*/
@Configuration
public class JwtTokenUtil {
public static final String CLAIM_KEY_USERNAME = "sub";
public static final String CLAIM_KEY_CREATED = "created";
@Value("${jwt.secret}")//秘钥
private String secret;
@Value("${jwt.expiration}")//失效时间
private Long expiration;
/**
* @param userDetails
* @return generteToken
* @author bai
* @date 2023/2/19 0019 16:32
* 根据用户名和时间创建token
*/
public String generteToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());
claims.put(CLAIM_KEY_CREATED, new Date());
return generateToken(claims);
}
/**
* @param token
* @return java.lang.String
* @author bai
* @date 2023/2/19 0019 16:39
* 从token中获取用户名
*/
public String getUserNameFromToken(String token) {
String userName;
try {
Claims claims = getClaimsFromToken(token);
//通过荷载claim就可以拿到用户名
userName = claims.getSubject();
} catch (Exception e) {
throw new RuntimeException(e);
}
return userName;
}
/**
* @param token
* @param userDetails
* @return boolean
* @author bai
* @date 2023/2/19 0019 16:47
* 判断token是否有效
*/
public boolean validateToken(String token, UserDetails userDetails) {
String name = getUserNameFromToken(token);
return name.equals(userDetails.getUsername()) && !isTokenExpired(token);
}
/**
* @param token
* @return java.lang.String
* @author bai
* @date 2023/2/19 0019 16:59
* 刷新token
*/
public String refreshToken(String token) {
Claims claims = getClaimsFromToken(token);
claims.put(CLAIM_KEY_CREATED, new Date());
return generateToken(claims);
}
/**
* @param token
* @return boolean
* @author bai
* @date 16:57
* 判断token是否可以刷新
*/
public boolean canRefresh(String token) {
return !isTokenExpired(token);
}
/**
* @param token
* @return boolean
* 判断token是否失效
* @author bai
* @date 2023/2/19 0019 16:51
*/
private boolean isTokenExpired(String token) {
Date date = getExpriedDateFromToken(token);
return date.before(new Date());
}
/**
* @param token
* @return java.util.Date
* 从token中获取过期时间
* @author bai
* @date 2023/2/19 0019 16:53
*/
private Date getExpriedDateFromToken(String token) {
Claims claims = getClaimsFromToken(token);
return claims.getExpiration();
}
/**
* @param token
* @return io.jsonwebtoken.Claims
* 从token中获取荷载
* @author bai
* @date 2023/2/19 0019 16:44
*/
private Claims getClaimsFromToken(String token) {
Claims claims = null;
try {
claims = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
e.printStackTrace();
}
return claims;
}
/**
* @param claims
* @return java.lang.String
* @author bai
* @date 2023/2/19 0019 16:36
* 根据荷载生成 jwt token
*/
private String generateToken(Map<String, Object> claims) {
return Jwts.builder()
.setClaims(claims)
.setExpiration(generateExpirationDate())
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
/**
* @return java.util.Date
* @author bai
* @date 2023/2/19 0019 16:37
* 生成token失效时间
*/
private Date generateExpirationDate() {
return new Date(System.currentTimeMillis() + expiration * 1000);
}
}
package com.bai.server.config.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author bai
* @date 2023年02月20日 19:09
* JWT登录 授权过滤器
*/
public class JwtAuthencationTokenFilter extends OncePerRequestFilter {
@Value("${jwt.tokenHeader}")
private String tokenHeader;
@Value("${jwt.tokenHead}")
private String tokenHead;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
//通过request获取请求头
String authHeader = httpServletRequest.getHeader(tokenHeader);
//验证头部,不存在,或者不是以tokenHead:Bearer开头
if (null != authHeader && authHeader.startsWith(tokenHead)) {
//存在就做一个字符串截取,获取登录的token
String authToken = authHeader.substring(tokenHead.length());
//jwt根据token获取用户名
String name = jwtTokenUtil.getUserNameFromToken(authToken);
//token存在用户名但是未登录
if ( !StringUtils.isEmpty(name) && null == SecurityContextHolder.getContext().getAuthentication()) {
//登录
UserDetails userDetails = userDetailsService.loadUserByUsername(name);
//验证token是否有效,重新设置用户对象
if (jwtTokenUtil.validateToken(tokenHead, userDetails)) {
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}
在线急等大佬解决
该文章展示了在SpringSecurity中使用JWT进行用户登录授权时的代码配置,包括生成、验证、刷新JWTtoken的方法以及一个JWT登录授权过滤器的实现。过滤器会检查请求头中的token并验证其有效性,确保用户已登录。
7604





