从 JWT 不记名令牌 Java 中检索用户 ID

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

我正在尝试从经过 JWT 令牌身份验证的用户那里获取 ID。当我向表中插入数据时,我想使用 ID 作为外键。但是我似乎在它自己的令牌上得到了一个空点异常,我相信我在这里误解了一些东西。

服务档案

@Service
public class JwtService {

    private static final String SECRET_KEY = "4528482B4D6251655468576D5A7134743777397A24432646294A404E63526655";
    public String extractUsername(String token) {
        return extractClaim(token, Claims::getSubject);
    }

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

    public String generateToken(UserDetails userDetails){
        return generateToken(new HashMap<>(), userDetails);
    }

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

    public boolean validToken(String token, UserDetails userDetails){
        final String username = extractUsername(token);
        return (username.equals(userDetails.getUsername())) && !tokenExpired(token);
    }

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

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

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

    private Key getSignInKey() {
        byte[] keyBytes = Decoders.BASE64.decode(SECRET_KEY);
        return Keys.hmacShaKeyFor(keyBytes);
    }
}

过滤文件

@Component
@RequiredArgsConstructor //skapar en constructor med private fields
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 jwtToken;
        final String email;
        if (authHeader == null || !authHeader.startsWith("Bearer ")){
            filterChain.doFilter(request, response);
            return;
        }
        jwtToken = authHeader.substring(7);
        email = jwtService.extractUsername(jwtToken);
        if (email != null && SecurityContextHolder.getContext().getAuthentication() == null){
            UserDetails userDetails = this.userDetailsService.loadUserByUsername(email);
            if(jwtService.validToken(jwtToken, userDetails)){
                UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
                        userDetails,
                        null,
                        userDetails.getAuthorities()
                );
                authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authToken);
            }
        }
        filterChain.doFilter(request, response);
    }
}

配置链

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfiguration {

    private final JwtAuthenticationFilter jwtAuthFilter;
    private final AuthenticationProvider authenticationProvider;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .csrf()
                .disable()
                .authorizeHttpRequests()
                    .requestMatchers("/api/v1/no-auth/**").permitAll()
                .anyRequest()
                .authenticated()
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authenticationProvider(authenticationProvider)
                .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }
}

由于经过身份验证的用户将在需要插入 SQL 数据库的网站上执行操作,因此我想使用发出请求的经过身份验证的用户的 ID。

我的控制器中的内容看起来像这样,但转换后的令牌字符串为空,即使我知道用户有一个有效的令牌。

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/venue")
public class VenueControllerAuth {

    private final VenueRepository repository;
    private final JwtService service;

    @PostMapping("/register")
    public ResponseEntity<String> registerVenue(@RequestBody Venue venue,
                                                HttpServletRequest request
    ){
        String token =  request.getHeader("Authorization").substring(7);
        User user = new User();
        user.setId(Long.parseLong(service.extractClaim(
                token, Claims::getId
        )));
        venue.setOwner(user);
        repository.save(venue);
        return ResponseEntity.ok("Venue added");
    }
}

java.lang.NumberFormatException: 无法解析空字符串

编辑:

JWT 令牌不应以这种方式使用。它不是为了用作存储会话而创建的。 正如 Toerktumlare 在评论中所说

java spring-security jwt bearer-token
© www.soinside.com 2019 - 2024. All rights reserved.