我在生产环境中有三个服务器以及一个全局负载均衡器。当第一个请求到来时,请求将被验证并生成JWT令牌,并且该令牌将被存储在Spring会话中的服务器中。但是,当新的请求来临并进入不同的服务器时,我被注销了。
我应该如何利用这里的资源?我阅读了一些关于在Redis中存储令牌的文章,但我不明白如何确切地使用它,或者我在这里有哪些不同选择?
在开发环境中,我只有一个服务器,所以无法测试它。
有人可以给我提供一些实际的例子,解决这个问题的具体方法是什么?
我在生产环境中有三个服务器以及一个全局负载均衡器。当第一个请求到来时,请求将被验证并生成JWT令牌,并且该令牌将被存储在Spring会话中的服务器中。但是,当新的请求来临并进入不同的服务器时,我被注销了。
我应该如何利用这里的资源?我阅读了一些关于在Redis中存储令牌的文章,但我不明白如何确切地使用它,或者我在这里有哪些不同选择?
在开发环境中,我只有一个服务器,所以无法测试它。
有人可以给我提供一些实际的例子,解决这个问题的具体方法是什么?
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private LoginSuccessHandler loginSuccessHandler;
@Autowired
private JWTRequestFilter jwtRequestFilter;
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(passwordEncoder());
return provider;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
...
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
...
}
}
JWT 工具文件,包含所有与 JWT 验证和生成相关的函数
@Component
public class JWTUtil {
public static final long EXPIRATION_TIME = 60 * 60 * 24;
public static final String TOKEN_PREFIX = "Bearer ";
public static final String HEADER_STRING = "Authorization";
@Value("${jwt.secret}")
private String secret;
public String getUsernameFromToken(String token) {
return getClaimFromToken(token, Claims::getSubject);
}
public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
final Claims claims = getAllClaimsFromToken(token);
return claimsResolver.apply(claims);
}
private Claims getAllClaimsFromToken(String token) {
return Jwts.parserBuilder().setSigningKey(secret.getBytes()).build().parseClaimsJws(token).getBody();
}
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return doGenerateToken(claims, userDetails.getUsername());
}
private String doGenerateToken(Map<String, Object> claims, String username) {
SecretKey key = Keys.hmacShaKeyFor(secret.getBytes());
return Jwts.builder().setClaims(claims)
.setSubject(username).setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME * 1000))
.signWith(key).compact();
}
public Date getExpirationDateFromToken(String token) {
return getClaimFromToken(token, Claims::getExpiration);
}
private Boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(new Date());
}
public boolean validateToken(String token, String requestUsername) {
final String username = getUsernameFromToken(token);
return (username.equals(requestUsername) && !isTokenExpired(token));
}
}
Jwt的一个重要部分是筛选器文件,它包含需要筛选或不需要筛选的URL。
@Service
public class JWTRequestFilter extends OncePerRequestFilter {
@Autowired
private JWTUtil jwtUtil;
@Autowired
private MyUserDetailsService myUserDetailsService;
Set<String> urls = new HashSet<String>(Arrays.asList("/api/login", "/api/register", "/api/"));
@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
String path = request.getRequestURI();
return urls.contains(path);
}
protected boolean shouldNotFilterErrorDispatch() {
return true;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String jwtToken = null;
String username = null;
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
if (cookie.getName().equals("Authorization")) {
jwtToken = cookie.getValue();
}
}
if (jwtToken != null) {
try {
username = jwtUtil.getUsernameFromToken(jwtToken);
} catch (IllegalArgumentException e) {
System.out.println("Unable to get JWT Token");
} catch (ExpiredJwtException e) {
System.out.println("JWT Token has expired");
}
} else {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
if (username != null) {
UserDetails userDetails = this.myUserDetailsService.loadUserByUsername(username);
if (!jwtUtil.validateToken(jwtToken, userDetails.getUsername())) {
logger.warn("JWT Token validation failed");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}
doFilter(request, response, filterChain);
}
}