Я использую токен 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");
}
}
}
SecurityConfig:
@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;
}
}
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;
}
}