如何将 JWT 令牌设置为每个用户唯一

问题描述 投票:0回答:0

我实现了 JWT 身份验证服务,该过程运行良好,并且我得到了 jwt 令牌作为每次身份验证的响应。问题是,当尝试访问另一个需要身份验证的端点时,我为 user1 获得的任何令牌都适用于其他用户,这意味着例如当尝试获取有关 user1 的配置文件的数据时,使用另一个用户的 jwt 身份验证令牌我可以在以下情况下获取 user1 的数据:他甚至没有进行身份验证。 我尝试在生成令牌时添加用户的声明,但问题仍然相同。 这是 JwtAuthenticationFilter 类:

@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private final JwtService jwtService;
    private final UserDetailsService userDetailsService;

    @Override
    protected void doFilterInternal(
            @NonNull HttpServletRequest request,
            @NonNull HttpServletResponse response,
            @NonNull FilterChain filterChain
    )
            throws ServletException, IOException {
        final String authHeader = request.getHeader("Authorization");
        final String jwt_token;
        final String userEmail;
        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            filterChain.doFilter(request, response);
            return;
        }
        jwt_token = authHeader.substring(7);
        userEmail = jwtService.extractUserEmail(jwt_token); // extract userEmail from JWT token
        if (userEmail != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = this.userDetailsService.loadUserByUsername(userEmail);
            if (jwtService.isTokenValid(jwt_token, userDetails)) {
                UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
                        userDetails,
                        null,
                        userDetails.getAuthorities()
                );
                authToken.setDetails(
                        new WebAuthenticationDetailsSource().buildDetails(request)
                );
                SecurityContextHolder.getContext().setAuthentication(authToken);
            }
            else {
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.getWriter().write("Unauthorized");
                return;
            }
        }
        filterChain.doFilter(request, response);
    }
}

这是 JwtService 类:

@Service
public class JwtService {

    //constant secret key that must change
    private static final String PRIVATE_KEY_PATH = "C:\\Users\\ihebt\\Documents\\security\\security\\src\\main\\resources/private.key";

/*    public JwtService(CustomLoginSuccessHandler authenticationSuccessHandler, CustomLoginFailureHandler authenticationFailureHandler) {
        this.authenticationSuccessHandler = authenticationSuccessHandler;
        this.authenticationFailureHandler = authenticationFailureHandler;
    }*/

    public String extractUserEmail(String jwtToken) {
        return extractClaim(jwtToken, Claims::getSubject);
    }

    public String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("email", userDetails.getUsername());

        return generateToken(claims, userDetails);
    }

    public String generateToken(
            Map<String, Object> extraClaims,
            UserDetails userDetails
    ) {
        return Jwts
                .builder()
                .setClaims(extraClaims)
                .setSubject(userDetails.getUsername())
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24))
                .signWith(getSignInKey(), SignatureAlgorithm.HS256)
                .compact();
    }

    public <T> T extractClaim(String token, Function<Claims, T> claimsResolver){
        final Claims claims = extractAllClaims(token);
        return claimsResolver.apply((claims));
    }

    public boolean isTokenValid(String token, UserDetails userDetails) {
        final String useremail = extractUserEmail(token);
        return (useremail.equals(userDetails.getUsername())) && !isTokenExpired(token);
    }

    private boolean isTokenExpired(String token) {
        return extractExpiration(token).before(new Date());
    }

    private Date extractExpiration(String token) {
        return extractClaim(token, Claims::getExpiration);
    }

    private Claims extractAllClaims(String jwt_token) {
        return Jwts
                .parserBuilder()
                .setSigningKey(getSignInKey())
                .build()
                .parseClaimsJws(jwt_token)
                .getBody();
    }

    private Key getSignInKey() {
        try {
            byte[] privateKeyBytes = Files.readAllBytes(Paths.get(PRIVATE_KEY_PATH));
            return Keys.hmacShaKeyFor(privateKeyBytes);
        } catch (IOException e) {
            throw new RuntimeException("Failed to read private key file", e);
        }
    }
}
spring-boot authentication security spring-security jwt
© www.soinside.com 2019 - 2024. All rights reserved.