我正在尝试从经过 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 在评论中所说