I followed the tutorial https://auth0.com/blog/implementing-jwt-authentication-on-spring-boot/ to integrate jwt to my application. I'm trying to add a custom successhandler to my application. Unfortunately, the successhandler is not triggering upon successful login request. I'm trying to return a user object instead of empty response with token in header. My handler is
#Component
public class AuthSuccessHandler implements AuthenticationSuccessHandler {
#Autowired
private ApplicationUserRepository userRepository;
#Autowired
private ObjectMapper objectMapper;
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
UserDetails user = (UserDetails) authentication.getPrincipal();
AuthInfo authInfo = new AuthInfo();
authInfo.setUser(userRepository.findOneByUserName(user.getUsername()));
authInfo.setToken(response.getHeader("Authentication"));
response.getWriter().write(objectMapper.writeValueAsString(authInfo));
response.setContentType("application/json");
response.setStatus(200);
}
}
I have configured it in WebSecurityConfigurer.configure() as
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.POST, SIGN_UP_URL).permitAll()
.antMatchers(HttpMethod.GET, "/public/**").permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.successHandler(successHandler)
.and()
.addFilter(new JWTAuthenticationFilter(authenticationManager(), securityConfig))
.addFilter(new JWTAuthorizationFilter(authenticationManager(), securityConfig))
// this disables session creation on Spring Security
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
#pvpkiran's solution didn't work. On debugging, I find that authenticationfilter is running twice and authorization filter is not triggering. Given below is the list of filters available in the application logs
Security filter chain: [
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
CorsFilter
LogoutFilter
JWTAuthenticationFilter
JWTAuthorizationFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
]
Try this. Create a local method like this.
public JwtAuthenticationTokenFilter authenticationTokenFilter() {
JwtAuthenticationTokenFilter filter = new JwtAuthenticationTokenFilter();
filter.setAuthenticationManager(authenticationManager());
filter.setAuthenticationSuccessHandler(successHandler);
return filter;
}
And change your configure method like this
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.POST, SIGN_UP_URL).permitAll()
.antMatchers(HttpMethod.GET, "/public/**").permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(authenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
Another point is it is better not to make your AuthSuccessHandler a bean (remove #Component) and create a object of AuthSucessHandler like this in Your security config. Reason being, If you declare your AuthSuccessHandler as a bean, spring will scan it and add two SuccessHandlers(
1. When it scans the bean,
2. When you add it in your SecurityConfig.
)
#EnableWebSecurity
#Configuration
public class JwtSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private ApplicationUserRepository userRepository;
#Autowired
private ObjectMapper objectMapper;
public JwtAuthenticationTokenFilter authenticationTokenFilter() {
JwtAuthenticationTokenFilter filter = new JwtAuthenticationTokenFilter();
filter.setAuthenticationManager(authenticationManager());
AuthSuccessHandler successHandler = new AuthSuccessHandler(userRepository, objectMapper):
filter.setAuthenticationSuccessHandler(successHandler);
return filter;
}
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.POST, SIGN_UP_URL).permitAll()
.antMatchers(HttpMethod.GET, "/public/**").permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(authenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
Change your AuthSuccessHandler like this
public class AuthSuccessHandler implements AuthenticationSuccessHandler {
private ApplicationUserRepository userRepository;
private ObjectMapper objectMapper;
public AuthSuccessHandler(ApplicationUserRepository userRepository, ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
this.userRepository = userRepository;
}
........
}
Related
Hello everyone I am writing Authentication using Spring Security and JWT tokens.
I add my own filter in the configuration. But the request is not included in the filter. Therefore, all requests to any address are executed, even without a token.
SecurityConfig.class
#Configuration
#EnableWebSecurity
#ComponentScan("my.pac")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JwtFilter jwtFilter;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().disable()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/register", "/auth").permitAll()
.and()
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Filter
#Component
public class JwtFilter extends GenericFilterBean {
public static final String AUTHORIZATION = "Authorization";
#Autowired
private JwtProvider jwtProvider;
#Autowired
private CustomUserDetailsService customUserDetailsService;
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
logger.info("do filter...");
String token = getTokenFromRequest((HttpServletRequest) servletRequest);
if (token != null && jwtProvider.validateToken(token)) {
String userLogin = jwtProvider.getLoginFromToken(token);
CustomUserDetails customUserDetails = customUserDetailsService.loadUserByUsername(userLogin);
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(customUserDetails, null, customUserDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(auth);
}
filterChain.doFilter(servletRequest, servletResponse);
}
private String getTokenFromRequest(HttpServletRequest request) {
String bearer = request.getHeader(AUTHORIZATION);
if (hasText(bearer) && bearer.startsWith("Bearer ")) {
return bearer.substring(7);
}
return null;
}}
upd:
this option also does not work for the filter:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().disable()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/register", "/auth").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
You only specified .antMatchers("/register", "/auth").permitAll(), to force authentication to other things you must add .anyRequest().authenticated()
So something like this
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().disable()
.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/register", "/auth").permitAll()
.and()
.anyRequest().authenticated()
.and()
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
}
hi how i can use this orders for my controller and restController ....
like -> order 1 for html view and order 2 for rest api
i want use it for webapp using rest and mvc in spring
Multiple Entry Points With Multiple HTTP Elements
i think i should using order in my controller class!
#Configuration
#EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailsService userDetailsService;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Configuration
#Order(1)
public static class ApiWebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/user/**").hasRole("EMPLOYEE")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/LoginPage")
.loginProcessingUrl("/authenticateTheUser")
.successHandler(customAuthenticationSuccessHandler)
.permitAll()
.and()
.logout().permitAll() `enter code here`
.and()
.exceptionHandling().accessDeniedPage("/access-denied");
}
}
#Configuration
#Order(2)
public class ApiWebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(m.authenticationProvider());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(HttpMethod.GET, "/api/**").hasRole("EMPLOYEE")
.and()
.httpBasic()
.and()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
}
i work on this problem and find way for using spring rest api and spring mvc in single
project this is easy to use them in one project with out security
for spring rest security and spring mvc security with login page and rest basic auth registery in a project we should use httpBasic()
and for url use
http://username:password#localhost:8080/api/members/
#Configuration
#EnableWebSecurity
public class MultipleEntryPointsSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserService userService;
#Autowired
private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
// this is filter for mappings for api and mvc mappings
// http://username:password#localhost:8080/api/members/
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/").hasRole("EMPLOYEE")
.antMatchers("/leaders/**").hasRole("MANAGER")
.antMatchers("/systems/**").hasRole("ADMIN")
.antMatchers(HttpMethod.GET, "/api/**").hasRole("EMPLOYEE")
.and()
.httpBasic()
.and()
.formLogin()
.loginPage("/showMyLoginPage")
.loginProcessingUrl("/authenticateTheUser")
.successHandler(customAuthenticationSuccessHandler)
.permitAll()
.and()
.logout().permitAll()
.and()
.exceptionHandling().accessDeniedPage("/access-denied");
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
auth.setUserDetailsService(userService); //set the custom user details service
auth.setPasswordEncoder(passwordEncoder()); //set the password encoder - bcrypt
return auth;
}
}
My Spring security works well but after some afk time I start getting tons of exceptions when the user goes to the pages.
I noticed that session and principal is null that's why I get error 500.
How do I redirect the user that to the login again?
Or I can simply remove the session timeout (i dont really need it)
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled=true)
#ComponentScan("pt.impactzero.atp")
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private MyUserDetailsService myUserDetailsService;
#Autowired
private AuthenticationSuccessHandler authenticationSuccessHandler;
#Autowired
private LogoutSuccessHandler logoutSuccessHandler;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/").hasAnyRole("Administrator" , "Member")
.and()
.formLogin()
.loginPage("/login").permitAll()
.defaultSuccessUrl("/dashboard",true)
.failureUrl("/login?error")
.successHandler(authenticationSuccessHandler)
.and()
.logout()
.logoutUrl("/logout").permitAll()
.logoutSuccessUrl("/login")
.logoutSuccessHandler(logoutSuccessHandler)
.and()
.csrf().disable();
}
#Override
public void configure(WebSecurity web) {
web.httpFirewall(allowUrlEncodedSlashHttpFirewall());
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService).passwordEncoder(passwordEncoder());
}
#Bean
public PasswordEncoder passwordEncoder() {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
return passwordEncoder;
}
#Bean
public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
DefaultHttpFirewall firewall = new DefaultHttpFirewall();
firewall.setAllowUrlEncodedSlash(true);
return firewall;
}
#Bean
public CommonsMultipartResolver filterMultipartResolver(){
return new CommonsMultipartResolver();
}
//Online users
#Bean
public ActiveUsers activeUsers(){
return new ActiveUsers();
}
}
If you want disable session, you can:
#Override
protected void configure(HttpSecurity http) throws Exception {
// disable session
http.sessionManagement().disable()
.authorizeRequests().antMatchers("/").hasAnyRole("Administrator" , "Member")
.and()
.formLogin()
.loginPage("/login").permitAll()
.defaultSuccessUrl("/dashboard",true)
.failureUrl("/login?error")
.successHandler(authenticationSuccessHandler)
.and()
.logout()
.logoutUrl("/logout").permitAll()
.logoutSuccessUrl("/login")
.logoutSuccessHandler(logoutSuccessHandler)
.and()
.csrf().disable();
}
if you want redirect user to login page, you can try this:
#Override
protected void configure(HttpSecurity http) throws Exception {
// redirect user to login page
http.sessionManagement().invalidSessionUrl("http://your.login.page").and()
.authorizeRequests().antMatchers("/").hasAnyRole("Administrator" , "Member")
.and()
.formLogin()
.loginPage("/login").permitAll()
.defaultSuccessUrl("/dashboard",true)
.failureUrl("/login?error")
.successHandler(authenticationSuccessHandler)
.and()
.logout()
.logoutUrl("/logout").permitAll()
.logoutSuccessUrl("/login")
.logoutSuccessHandler(logoutSuccessHandler)
.and()
.csrf().disable();
}
Hi I have implemented Spring security in my spring boot web application with JWT filters. But the default authentication is happening at url http://localhost:8080/login . How to change /login to some url I need like /rest/auth/login?
My WebSecurity class is
#EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
public WebSecurity( UserDetailsService userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder )
{
this.userDetailsService = userDetailsService;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}
#Override
protected void configure( HttpSecurity http ) throws Exception
{
http.cors().and().csrf().disable().authorizeRequests().antMatchers(HttpMethod.POST, "/rest/auth/**").permitAll()
.antMatchers("/static/*").permitAll().antMatchers("/").permitAll()
/* .anyRequest().authenticated() */.and()
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
.addFilter(new JWTAuthorizationFilter(authenticationManager()));
}
#Override
public void configure( AuthenticationManagerBuilder auth ) throws Exception
{
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}
#Override
public void configure( org.springframework.security.config.annotation.web.builders.WebSecurity web )
throws Exception
{
web.ignoring().antMatchers("/static/**");
}
#Bean
CorsConfigurationSource corsConfigurationSource()
{
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}
}
I have a login page in my resource folder under static directory. The way Spring security works is, when user sends userName and password from the form, client has to send those credentials to /login path in the server, so that spring security verifies those credentials and creates token. But I want to change that default path /login to /rest/auth/login
In your AuthenticationFilter you can call setFilterProcessesUrl during construction, example:
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;
public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
setFilterProcessesUrl("/api/v1/tokens"); // <--- like this
}
...
Hope it helps.
You need to tweak the WebSecurityConfig.java and JWTAuthenticationFilter.
#Override
protected void configure( HttpSecurity http ) throws Exception
{
http.csrf().disable()
.authorizeRequests()
.antMatchers("/rest/noauth/**").permitAll()
.antMatchers("/rest/login").permitAll()
.antMatchers("/rest/logout").permitAll()
.antMatchers("/src/**").permitAll()
.antMatchers("/v2/api-docs/**", "/configuration/ui/**", "/swagger-resources/**",
"/configuration/security/**", "/swagger-ui.html/**", "/webjars/**")
.permitAll()
.anyRequest().authenticated()
.and()
.logout().addLogoutHandler(logoutHandler).logoutSuccessHandler(logoutSuccessHandler)
.logoutUrl("/rest/logout")
.and()
.addFilterBefore(
new JWTAuthenticationFilter("/rest/login",
UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new JWTAuthorizationFilter(authenticationManager(), authTokenModelRepository),
UsernamePasswordAuthenticationFilter.class);
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
and make your JWTAuthenticationFilter extends AbstractAuthenticationProcessingFilter which has a constructor which takes the filterProcessingURl and I passed /rest/login as the parameter.
public class JWTAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(JWTAuthenticationFilter.class);
private AuthenticationManager authenticationManager;
private TokenService tokenService;
private UserModel credentials;
private RefreshTokenService refreshTokenService;
private AuthTokenModelRepository authTokenModelRepository;
private UserModelRepository userModelRepository;
public JWTAuthenticationFilter( String loginUrl, AuthenticationManager authenticationManager,
TokenService tokenService, RefreshTokenService refreshTokenService,
AuthTokenModelRepository authTokenModelRepository, UserModelRepository userModelRepository )
{
super(new AntPathRequestMatcher(loginUrl));
}
After the above configuration, the JWTAuthenticationFilter will be executed for the request /rest/login.
Just to complement Jordy Baylac's answer: in Kotlin I was struggling how to set the filter once I'm injecting the dependencies via main constructor. My solution was do something like this:
class AuthenticationFilter(
authenticationManager: AuthenticationManager?,
private var jwtUtilsComponent: JwtUtilsComponent,
) : UsernamePasswordAuthenticationFilter() {
private val authManager: AuthenticationManager? = authenticationManager
init {
setFilterProcessesUrl("/${ApiProperties.BASE_PATH}/login")
}
// more code
}
then it worked very well.
In the configure method try to add loginProcessungUrl() method. You can set the value in the parameter
.addFilter(new JWTAuthorizationFilter(authenticationManager()))
.loginProcessingUrl(LOGIN_URL);
You need to provide the url to the login page and the url that would process the authentication. This can be done by overriding the method like this:
#Override
protected void configure( HttpSecurity http ) throws Exception
{
http.cors().and().csrf().disable().
authorizeRequests().
antMatchers(HttpMethod.POST, "/rest/auth/**").
permitAll()
.antMatchers("/static/*").permitAll()
.antMatchers("/").permitAll()
.and().formLogin().
/*This is where the juice is*/
loginPage("/login").loginProcessingUrl("/rest/auth/login")
/* .anyRequest().authenticated() */.and()
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
.addFilter(new JWTAuthorizationFilter(authenticationManager()));
}
The loginPage("/login") can be replaced with the route to your static login page while the loginProcessingUrl is the url of the controller that processes your login logic. Ensure that controllers exist for both /login and /loginProcesingUrl.
Modify "HttpSecurity", as follows, example:
#Override
protected void configure( HttpSecurity http ) throws Exception {
http.cors().and().csrf().disable().authorizeRequests().antMatchers(HttpMethod.POST, "/rest/auth/**").permitAll()
.antMatchers("/static/*").permitAll().antMatchers("/").permitAll()
/* .anyRequest().authenticated() */
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/rest/auth/login")
.permitAll()
.and()
.logout()
.permitAll();
.and()
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
.addFilter(new JWTAuthorizationFilter(authenticationManager()));
}
I have a custom UserDetailsService:
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
private AccountRepository accountRepository;
#Autowired
private PasswordEncoder passwordEncoder;
private static Logger logger = LoggerFactory.getLogger(JWTLoginFilter.class);
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
CustomUserDetails account = accountRepository.findByUsername(username);
if (account != null) {
return account;
} else {
throw new UsernameNotFoundException("could not find the user '" + username + "'");
}
}
public void saveUser(String userName, String password) {
CustomUserDetails userDetails = new CustomUserDetails(userName, passwordEncoder.encode(password), true, true, true,true, AuthorityUtils.commaSeparatedStringToAuthorityList("USER_ROLE"));
accountRepository.save(userDetails);
logger.debug("New user with username " + userName + " was created");
}
}
and I have a sign up filter (which handles creating new users) and extends AbstractAuthenticationProcessingFilter:
public class JWTSignupFilter extends AbstractAuthenticationProcessingFilter {
#Autowired
private CustomUserDetailsService userDetailService;
private static Logger logger = LoggerFactory.getLogger(JWTLoginFilter.class);
public JWTSignupFilter(String url, AuthenticationManager authManager) {
super(new AntPathRequestMatcher(url, HttpMethod.POST.toString()));
setAuthenticationManager(authManager);
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request,HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
CustomUserDetails creds = new ObjectMapper().readValue(request.getInputStream(), CustomUserDetails.class);
if (userDetailService.loadUserByUsername(creds.getUsername()) != null) {
logger.debug("Duplicate username " + creds.getUsername());
throw new AuthenticationException("Duplicate username") {
private static final long serialVersionUID = 1L;
};
}
userDetailService.saveUser(creds.getUsername(), creds.getPassword());
return getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(creds.getUsername(),creds.getPassword()));
}
#Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication auth) throws IOException, ServletException {
TokenAuthenticationService.addAuthentication(response, auth.getName());
chain.doFilter(request, response);
}
}
I get null pointer exception when the execution reaches userDetailService.loadUserByUsername, which means autowiring didn't work.
I tried implementing ApplicationContextAware like the following, but it is still Null. I also annotated JWTSignupFilter with #Service but it didn't work either. Any idea how to fix this issue ?
public class JWTSignupFilter extends AbstractAuthenticationProcessingFilter implements ApplicationContextAware {
private CustomUserDetailsService userDetailService;
.....
#Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
userDetailService = applicationContext.getBean(CustomUserDetailsService.class);
}
}
This is the overriden configure method in WebSecurityConfigurerAdapter, where login filter comes in to the play:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
.and()
.authorizeRequests()
.antMatchers("/signup").permitAll()
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.logout().logoutUrl("/logout").logoutSuccessHandler(logoutHandler).logoutSuccessUrl("/login").invalidateHttpSession(true)
.and()
// We filter the api/signup requests
.addFilterBefore(
new JWTSignupFilter("/signup", authenticationManager()),
UsernamePasswordAuthenticationFilter.class)
// We filter the api/login requests
.addFilterBefore(
new JWTLoginFilter("/login", authenticationManager()),
UsernamePasswordAuthenticationFilter.class)
// And filter other requests to check the presence of JWT in
// header
.addFilterBefore(
new JWTAuthenticationFilter(userDetailsServiceBean()),
UsernamePasswordAuthenticationFilter.class);
}
Try this:
Add below code into your configuration file:
#Bean
public JWTSignupFilter jWTSignupFilter() throws Exception {
return new JWTSignupFilter("/login", authenticationManager());
}
Add below line into your WebSecurityConfigurerAdapter extended class
#Autowired
JWTLoginFilter jWTSignupFilter
and replace
.addFilterBefore(
new JWTLoginFilter("/login", authenticationManager()),
UsernamePasswordAuthenticationFilter.class)
with
.addFilterBefore(
jWTSignupFilter,
UsernamePasswordAuthenticationFilter.class)
Updated
Your WebSecurityConfigurerAdapter extended class should look like so:
public Class CustomConfigurationClass extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
.and()
.authorizeRequests()
.antMatchers("/signup").permitAll()
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.logout().logoutUrl("/logout").logoutSuccessHandler(logoutHandler).logoutSuccessUrl("/login").invalidateHttpSession(true)
.and()
// We filter the api/signup requests
.addFilterBefore(
jWTSignupFilter(),
UsernamePasswordAuthenticationFilter.class)
// We filter the api/login requests
.addFilterBefore(
new JWTLoginFilter("/login", authenticationManager()),
UsernamePasswordAuthenticationFilter.class)
// And filter other requests to check the presence of JWT in
// header
.addFilterBefore(
new JWTAuthenticationFilter(userDetailsServiceBean()),
UsernamePasswordAuthenticationFilter.class);
}
#Bean
public JWTSignupFilter jWTSignupFilter() throws Exception {
return new JWTSignupFilter("/signup", authenticationManager());
}
}