在 Spring Security 中检查令牌的 NullPointerException
Posted
技术标签:
【中文标题】在 Spring Security 中检查令牌的 NullPointerException【英文标题】:NullPointerException for checking token in Spring Security 【发布时间】:2020-07-05 16:39:10 【问题描述】:我正在使用 jwt 令牌进行授权,当我使用令牌发送请求时,我得到空指针异常和 500 错误。如何解决这个问题?我可以获得授权令牌,但不能使用它。
错误:
java.lang.NullPointerException: null
at com.ilya.testapp.security.JwtTokenProvider.getAuthentication(JwtTokenProvider.java:64) ~[classes/:na]
at com.ilya.testapp.security.JwtTokenFilter.doFilter(JwtTokenFilter.java:29) ~[classes/:na]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
...
登录控制器:
@RestController
@RequestMapping(value = "/api/v1/auth/")
public class AuthenticationRestControllerV1
private final AuthenticationManager authenticationManager;
private final JwtTokenProvider jwtTokenProvider;
private final UserRepository userRepository;
public AuthenticationRestControllerV1(AuthenticationManager authenticationManager, JwtTokenProvider jwtTokenProvider, UserRepository userRepository)
this.authenticationManager = authenticationManager;
this.jwtTokenProvider = jwtTokenProvider;
this.userRepository = userRepository;
@PostMapping("login")
public ResponseEntity login(@RequestBody AuthenticationRequestDto requestDto)
try
String username = requestDto.getUsername();
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, requestDto.getPassword()));
User user = userRepository.findByUsername(username);
if (user == null)
throw new UsernameNotFoundException("User with username: " + username + " not found");
String token = jwtTokenProvider.createToken(username, user.getRoleList());
Map<Object, Object> response = new HashMap<>();
response.put("username", username);
response.put("token", token);
return ResponseEntity.ok(response);
catch (AuthenticationException e)
throw new BadCredentialsException("Invalid username or password");
安全配置:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
private final JwtTokenProvider jwtTokenProvider;
public SecurityConfig(JwtTokenProvider jwtTokenProvider)
this.jwtTokenProvider = jwtTokenProvider;
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception
return super.authenticationManagerBean();
@Override
protected void configure(HttpSecurity http) throws Exception
http
.cors()
.and()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/api/v1/auth/login").permitAll()
.antMatchers("/api/v1/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.apply(new JwtConfigurer(jwtTokenProvider));
@Bean
public CorsConfigurationSource corsConfigurationSource()
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(List.of("*"));
configuration.setAllowedMethods(List.of("HEAD",
"GET", "POST", "PUT", "DELETE", "PATCH"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(List.of("Authorization", "Cache-Control", "Content-Type"));
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
JwtTokenFilter:
public class JwtTokenFilter extends GenericFilterBean
private JwtTokenProvider jwtTokenProvider;
public JwtTokenFilter(JwtTokenProvider jwtTokenProvider)
this.jwtTokenProvider = jwtTokenProvider;
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain)
throws IOException, ServletException
String token = jwtTokenProvider.resolveToken((HttpServletRequest) req);
System.out.println("req = "+req+" token1 = "+token);
if (token != null && jwtTokenProvider.validateToken(token))
Authentication auth = jwtTokenProvider.getAuthentication(token);
if (auth != null)
SecurityContextHolder.getContext().setAuthentication(auth);
filterChain.doFilter(req, res);
JwtTokenProvider:
@Component
public class JwtTokenProvider
@Value("$jwt.token.secret")
private String secret;
@Value("$jwt.token.expired")
private long validityInMilliseconds;
private UserPrincipalDetailsService userPrincipalDetailsService;
public JwtTokenProvider()
public JwtTokenProvider(UserPrincipalDetailsService userPrincipalDetailsService)
this.userPrincipalDetailsService = userPrincipalDetailsService;
public JwtTokenProvider(String secret, long validityInMilliseconds, UserPrincipalDetailsService userPrincipalDetailsService)
this.secret = secret;
this.validityInMilliseconds = validityInMilliseconds;
this.userPrincipalDetailsService = userPrincipalDetailsService;
@Bean
public BCryptPasswordEncoder passwordEncoder()
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
return bCryptPasswordEncoder;
public String createToken(String username, List<String> roles)
Claims claims = Jwts.claims().setSubject(username);
claims.put("roles",roles);
Date now = new Date();
Date validity = new Date(now.getTime() + validityInMilliseconds);
return Jwts.builder()//
.setClaims(claims)//
.setIssuedAt(now)//
.setExpiration(validity)//
.signWith(SignatureAlgorithm.HS256, secret)//
.compact();
public Authentication getAuthentication(String token)
UserDetails userDetails = this.userPrincipalDetailsService.loadUserByUsername(getUsername(token));
return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities());
public String getUsername(String token)
return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody().getSubject();
public boolean validateToken(String token)
try
Jws<Claims> claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token);
if (claims.getBody().getExpiration().before(new Date()))
return false;
return true;
catch (JwtException | IllegalArgumentException e)
throw new JwtAuthenticationException("JWT token is expired or invalid");
public String resolveToken(HttpServletRequest req)
String bearerToken = req.getHeader("Authorization");
if (bearerToken != null && bearerToken.startsWith("Bearer_"))
return bearerToken.substring(7, bearerToken.length());
return null;
JwtConfigurer:
public class JwtConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity>
private JwtTokenProvider jwtTokenProvider;
public JwtConfigurer(JwtTokenProvider jwtTokenProvider)
this.jwtTokenProvider = jwtTokenProvider;
@Override
public void configure(HttpSecurity httpSecurity) throws Exception
JwtTokenFilter jwtTokenFilter = new JwtTokenFilter(jwtTokenProvider);
httpSecurity.addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class);
UserPrincipalDetailService:
@Service
public class UserPrincipalDetailsService implements UserDetailsService
private final UserRepository userRepository;
public UserPrincipalDetailsService(UserRepository userRepository)
this.userRepository = userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
User user = this.userRepository.findByUsername(username);
if (user == null)
throw new UsernameNotFoundException("User with username: " + username + " not found");
UserPrincipal userPrincipal = new UserPrincipal(user);
return userPrincipal;
用户主体:
public class UserPrincipal implements UserDetails
private User user;
public UserPrincipal(User user)
this.user = user;
@Override
public Collection<? extends GrantedAuthority> getAuthorities()
List<GrantedAuthority> authorities = new ArrayList<>();
// Extract list of permissions (name)
this.user.getPermissionList().forEach(p ->
GrantedAuthority authority = new SimpleGrantedAuthority(p);
authorities.add(authority);
);
// Extract list of roles (ROLE_name)
this.user.getRoleList().forEach(r ->
GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_" + r);
authorities.add(authority);
);
return authorities;
@Override
public String getPassword()
return this.user.getPassword();
@Override
public String getUsername()
return this.user.getUsername();
@Override
public boolean isAccountNonExpired()
return true;
@Override
public boolean isAccountNonLocked()
return true;
@Override
public boolean isCredentialsNonExpired()
return true;
@Override
public boolean isEnabled()
return this.user.getActive() == 1;
【问题讨论】:
你解决了吗?同样的问题 【参考方案1】:很难说,因为你删除了所有的行号。但最后你在 JWTTokenprovider 的 getAuthentication 方法中有一个 NullPointerException。你的 getUsername(token) 方法坏了吗?
【讨论】:
以上是关于在 Spring Security 中检查令牌的 NullPointerException的主要内容,如果未能解决你的问题,请参考以下文章
Spring security OAuth - 检查访问令牌的有效性?