Я использую Spring Core, Spring MVC, Spring REST, JWT.
Привет всем!
Я изучаю Spring Security и столкнулся с проблемой.
Я хотел бы сделать аутентификацию на основе JWT; У меня есть контроллер Rest с 3 простыми методами:
Первый метод должен быть доступен для всех, второй только для зарегистрированных пользователей, а третий только для администраторов. И хотя это работает, у меня есть еще одна проблема.
Проблема в том, что мой фильтр выбрасывает (не напрямую, потому что ноль возвращается token = header.substring(7)
) NullPointerException
каждый раз после запуска, даже когда он еще не получил ни одного запроса (могу ошибаться, надеюсь, этот код прояснит это). Можно ли настроить фильтр для обработки только выбранных запросов или, возможно, мой подход неверен?
Спасибо за помощь!
Ошибка:
java.lang.NullPointerException
at com.sample.config.JwtFilter.getAuthenticationByToken(JwtFilter.java:50)
at com.sample.config.JwtFilter.doFilterInternal(JwtFilter.java:36)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:526)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:678)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1587)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Unknown Source)
My JwtFilter
:
public class JwtFilter extends BasicAuthenticationFilter {
public JwtFilter(AuthenticationManager authenticationManager) {
super(authenticationManager);
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
String header=request.getHeader("authorization");
UsernamePasswordAuthenticationToken authResult=getAuthenticationByToken(header);
SecurityContextHolder.getContext().setAuthentication(authResult);
chain.doFilter(request, response);
}
private UsernamePasswordAuthenticationToken getAuthenticationByToken(String header) {
String token = header.substring(7);
Jws<Claims> claims = Jwts.parser().setSigningKey("fQx]n}YmL)WuHjL".getBytes()).parseClaimsJws(token);
String username=claims.getBody().get("name").toString();
String role = claims.getBody().get("role").toString();
return new UsernamePasswordAuthenticationToken(username,null,Collections.singleton(new SimpleGrantedAuthority(role)));
}
}
Моя конфигурация:
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter{
@Override
protected AuthenticationManager authenticationManager() throws Exception {
return new AuthenticationManager() {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
return null;
}
};
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/api/test2").authenticated() .antMatchers("/api/test3").hasRole("ADMIN")
.and()
.addFilter(new JwtFilter(authenticationManager())); }
}
public class SpringSecurityWebInitializer extends AbstractSecurityWebApplicationInitializer{
}
Контроллер:
@RestController
@RequestMapping("/api")
public class TestApi {
@GetMapping("/test1")
public String test1()
{
return "test1";//for everyone
}
@GetMapping("/test2")
public String test2()
{
return "test2";//only for logged in
}
@GetMapping("/test3")
public String test3()
{
return "test3";//only for admins
}
}