I have a springboot micro service. This is called by a React client. The react client authenticates the user via a login form and logs her in. It uses our custom Authentication service for that. After a successful login, a JWT kind of token is issued and saved in browser's local storage which then is submitted by the client in HTTP Authorization header when calling the microservice. Here's a code snippet from my implementation.
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// ...
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.csrf().disable().headers().frameOptions().disable()
.and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().authorizeRequests().antMatchers("/api/**").authenticated()
.antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/swagger-resources/configuration/ui").permitAll()
.antMatchers("/health/**").permitAll()
.and()
.addFilterBefore(new JWTAuthorizationFilter(new MyAuthenticationProvider()),
UsernamePasswordAuthenticationFilter.class);
}
}
I have my own AuthenticationProvider
implementation for doing the actual authentication against our internal auth service. Here's my filter class. I have removed unnecessary code for the sake of simplicity.
public class JWTAuthorizationFilter extends OncePerRequestFilter {
private static final String UNAUTHORIZED_ERROR = "UNAUTHORIZED";
public static final String X_AUTHORIZATION_HEADER = "X-Authorization";
private static final String BEARER = "Bearer ";
private final Logger log = LoggerFactory.getLogger(JWTAuthorizationFilter.class);
private final AuthenticationProvider authenticationProvider;
public JWTAuthorizationFilter(AuthenticationProvider authProvider) {
super();
this.authenticationProvider = authProvider;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
try {
String token = resolveToken(request);
Authentication authentication = this.authenticationProvider
.authenticate(new UsernamePasswordAuthenticationToken(null, token));
SecurityContextHolder.getContext().setAuthentication(authentication);
// invoking the next chain in the filter.
filterChain.doFilter(request, response);
} catch (AuthenticationException e) {
log.error("Security exception for user {} - {}", e.getMessage());
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, UNAUTHORIZED_ERROR);
}
}
private String resolveToken(HttpServletRequest request) {
return request.getHeader(X_AUTHORIZATION_HEADER);
}
}
Everything works fine. Then I had a code review and at that moment a coulegue asked me to use AbstractAuthenticationProcessingFilter
instead of OncePerRequestFilter
/GenericFilterBean
. I checked the documentation [1], and it says that the AbstractAuthenticationProcessingFilter
is mainly used for browser-based HTTP-based authentication requests.
By the way I tried implementing that by moving around my currently working logic there, and hooked it up with my springboot microservice. But unfortunately when I send a request it gives me 301 moved permanently HTTP status code with some HTML for a login form.
Here's my question.
- Can I use
AbstractAuthenticationProcessingFilter
for this token authentication. If so how it can be done? - Why I am getting 301 moved permanently ERROR after hooking it up with my service.
- Are there any possible errors, vulnerabilities, or performance issues that might occur with my current approach?
- What other ways are there for token based authentication, and what are their pros and cons?
I checked out the spring security reference guide, but could not find concrete answers to the above questions.
Unfortunately I can't share my code, since it uses some proprietary libraries which are internal to the organization. My apologies for that. Any help is appreciated.