I started a new spring 3.0.2 project with spring security and I'm trying to create a register/login rest API for now as I am a begineer.
I managed to get a this working but after when my user is authentified I have a 3rd controller that will display information. However, I am always getting 403 response.
I am using the JWT token library to manage request here are some piece of code of my project.
my configuration for filtering request as you can only 2 endpoints are free to visit and I want all the rest to be locked to authentificated users only.
private final Filter tokenAuthentificationFilter;
private final AuthenticationProvider authentificationProvider;
#Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf()
.and()
.authorizeHttpRequests()
.requestMatchers("/api/v1/auth/**", "/api/v1/test-controller")
.permitAll()
.anyRequest()
.authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authenticationProvider(authentificationProvider)
.addFilterBefore(tokenAuthentificationFilter, UsernamePasswordAuthenticationFilter.class);
return httpSecurity.build();
}
if I'm not connected the /api/v1/auth and /test-controller works correctly but when I'm connected I have a "protected" endpoint /protected and it returns 403
below it's my tokenAuthentificationFilter class
#Component
#RequiredArgsConstructor
public class TokenAuthentificationFilter extends OncePerRequestFilter {
private final JwtService jwtService;
private final UserDetailsService userDetailsService;
#Override
protected void doFilterInternal( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain
) throws ServletException, IOException {
String authorizationHeader = request.getHeader("Authorization");
String authToken;
String userEmail;
if(authorizationHeader == null || !authorizationHeader.startsWith("Bearer")){
filterChain.doFilter(request, response);
return;
}
authToken = authorizationHeader.substring(7);
userEmail = jwtService.extractEmail(authToken);// TODO extract userEmail from JWT Token;
if(userEmail != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(userEmail);
if(jwtService.isTokenValid(authToken, userDetails)) {
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
userDetails,
null,
userDetails.getAuthorities()
);
authenticationToken.setDetails(
new WebAuthenticationDetailsSource().buildDetails(request)
);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
filterChain.doFilter(request, response);
}
}
No log error in my console
code seems fine to me but this might not be the one causing problem, try putting in a few print statements inside your code. See the flow of requests from filters to endpoint. Then try hitting the protected endpoint, it should give you an idea where's the request is blocked. Then try to work from there, that's how i solved most of spring security problems.
Related
I have secured my application using oauth2 standard flow with amazon cognito. It works fine.
Sometimes i want to link to my webapp through my mobile app, and i dont want the user to sign in again. How do i create an #AnonymousAllowed endpoint that takes in an access token, authenticates using spring security and redirects to the homepage of my application?
I've tried creating an endpoint that returns the jsessionid, then another anonymous endpoint that accepts a jsessionid, sets the cookie and redirects to the homepage, but it didnt work.
I've tried setting the authorization header to the access token. But i feel like that wont work properly because the token will expire after few minutes, and spring wont handle authorization for me, rather i have to do it "manually"
I don't know if this can help in your situation. But you can check if anything you can refer from below. It's a custom filter with custom token validator.
You can use Custom TokenAuthenticationFilter by extending AbstractAuthenticationProcessingFilter
public class CustomTokenAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
#Autowired
private TokenValidatorService tokenValidatorService;
public CustomTokenAuthenticationFilter(final RequestMatcher requiresAuth) {
super(requiresAuth);
}
#Override
public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {
String token= httpServletRequest.getHeader(CommonConstants.OAUTH_HEADER_KEY_AUTHORIZATION);
//Get the custom header
//Validate token using custom validator based on header value
Optional<OAuthResponseData> oauthResponseData = tokenValidatorService.validateAccessToken(token, provider);
...
Authentication requestAuthentication = new UsernamePasswordAuthenticationToken(oauthResponseData.get(), oauthResponseData.get().getOauthToken());
return getAuthenticationManager().authenticate(requestAuthentication);
}
#Override
protected void successfulAuthentication(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain, final Authentication authResult) throws IOException, ServletException {
SecurityContextHolder.getContext().setAuthentication(authResult);
chain.doFilter(request, response);
}
}
In TokenValidatorService you can implement OAuth2TokenValidator to validate the token
Spring Security config class:
public class SecurityConfig extends GlobalAuthenticationConfigurerAdapter {
#Configuration
public static class CustomTokenSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
protected CustomTokenAuthenticationProvider customTokenAuthenticationProvider;
#Override
public void configure(final WebSecurity webSecurity) {
webSecurity.ignoring()
...
}
#Override
protected void configure(HttpSecurity http) throws Exception
{
http .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling()
.and()
.addFilterBefore(tokenAuthenticationFilter(), AnonymousAuthenticationFilter.class)
.authorizeRequests()
.requestMatchers(PROTECTED_URLS).authenticated()
.and()
.csrf().disable()
.formLogin().disable()
.httpBasic().disable()
.logout().disable();
}
#Bean
public CustomTokenAuthenticationFilter tokenAuthenticationFilter() throws Exception {
final CustomTokenAuthenticationFilter filter = new CustomTokenAuthenticationFilter(PROTECTED_URLS);
filter.setAuthenticationManager(authenticationManager());
// filter.setAuthenticationSuccessHandler(successHandler());
return filter;
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customTokenAuthenticationProvider);
}
}
}
The following config (filterChain) works fine in SpringBoot-2.7.5, but after I tried to test it in SpringBoot-3.0.0-RC1, it is not working and shows the following message, anything I need to change if want to migrate to Spring-Boot-3.0.0. Thanks.
{
"timestamp": 1667794247614,
"status": 401,
"error": "Unauthorized",
"message": "An Authentication object was not found in the SecurityContext",
"path": "/api/admin/1" }
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationProvider).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/**").permitAll()
// private endpoints
.anyRequest().authenticated();
http.addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
The following is the jwtTokenFilter:
#Component
public class **JwtTokenFilter** extends OncePerRequestFilter {
#Autowired
private JwtTokenUtil jwtTokenUtil;
#Autowired
private JPAUserDetailService jpaUserDetailService;
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
// Get authorization header and validate
final String header = request.getHeader(HttpHeaders.AUTHORIZATION);
if (isEmpty(header) || !header.startsWith("Bearer ")) {
chain.doFilter(request, response);
return;
}
// Get jwt token and validate
final String token = header.split(" ")[1].trim();
if (!jwtTokenUtil.validate(token)) {
chain.doFilter(request, response);
return;
}
// Get user identity and set it on the spring security context
UserDetails userDetails = jpaUserDetailService.loadUserByUsername(jwtTokenUtil.getUsername(token));
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, (userDetails == null ? null : userDetails.getAuthorities()));
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(request, response);
}
}
In Spring Security 6, the default behavior is that the SecurityContextHolderFilter will only read the SecurityContext from SecurityContextRepository and populate it in the SecurityContextHolder. Users now must explicitly save the SecurityContext with the SecurityContextRepository if they want the SecurityContext to persist between requests. This removes ambiguity and improves performance by only requiring writing to the SecurityContextRepository (i.e. HttpSession) when it is necessary.
SecurityContextHolder.setContext(securityContext);
securityContextRepository.saveContext(securityContext, httpServletRequest, httpServletResponse);
See https://docs.spring.io/spring-security/reference/5.8/migration.html#_explicit_save_securitycontextrepository
If that doesn't work, try going back to the 5.x default:
http
.securityContext((securityContext) ->
.requireExplicitSave(false)
)
I changed some codes as following, but still not working.
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
// Get authorization header and validate
final String header = request.getHeader(HttpHeaders.AUTHORIZATION);
if (isEmpty(header) || !header.startsWith("Bearer ")) {
chain.doFilter(request, response);
return;
}
// Get jwt token and validate
final String token = header.split(" ")[1].trim();
if (!jwtTokenUtil.validate(token)) {
chain.doFilter(request, response);
return;
}
// Get user identity and set it on the spring security context
UserDetails userDetails = jpaUserDetailService.loadUserByUsername(jwtTokenUtil.getUsername(token));
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, (userDetails == null ? null : userDetails.getAuthorities()));
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextImpl scix = new SecurityContextImpl(authentication);
SecurityContextHolder.setContext(scix);
RequestAttributeSecurityContextRepository securityContextRepository = new RequestAttributeSecurityContextRepository();
securityContextRepository.saveContext(scix, request, response);
chain.doFilter(request, response);
}
And the configs following:
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationProvider)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeHttpRequests((requests) - > requests
.requestMatchers("/swagger-ui", "/rest-api-docs").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class)
.securityContext((securityContext) - >
securityContext.requireExplicitSave(false)
);
return http.build();
}
I've implmemented security in my spring boot microservices project, the requirment is to have
two types of configurations, one for user request (from angular) and one from other services.
The design is to use JWT token for user request and API key for system calls.
Here is the config file (one file) but have also try to split it to two files with no impact:
#Configuration
#EnableWebSecurity
public class SecurityConfig {
#Configuration
#Order(1)
public static class APISecurityConfig extends WebSecurityConfigurerAdapter {
#Value("${my.api.key.header}")
private String principalRequestHeader;
#Value("${my.api.key.token}")
private String principalRequestValue;
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.cors().disable().csrf().disable();
httpSecurity
.antMatcher("/api/users/**")
.authorizeRequests() //
.anyRequest().authenticated()
.and()
.addFilterBefore(new APIKeyAuthFilter(principalRequestHeader, principalRequestValue), UsernamePasswordAuthenticationFilter.class);
}
}
#Order(2)
#Configuration
public static class MySecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailsService userDetailsService;
#Bean
public AuthTokenFilter authenticationJwtTokenFilter() {
return new AuthTokenFilter();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/api/users/**");
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.cors().disable().csrf().disable();
httpSecurity
.authorizeRequests()
.antMatchers("/users/UserEmailExist", "/users/User/Add", "/users/Authenticate",
"/users/User/ChangePassword")
.permitAll()
.and()
.authorizeRequests()
.antMatchers("/users/**").hasAnyRole(ROLE_ADMIN_USER, ROLE_MANAGER_USER)
.anyRequest().authenticated()
.and()
.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
}
Each config has a filter attached to it, here the api one:
public class APIKeyAuthFilter extends GenericFilterBean {
private String principalRequestHeader;
private String principalRequestValue;
public APIKeyAuthFilter(String principalRequestHeader, String principalRequestValue) {
super();
this.principalRequestHeader = principalRequestHeader;
this.principalRequestValue = principalRequestValue;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
if(request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
String apiKey = getApiKey((HttpServletRequest) request);
if(apiKey != null) {
if(apiKey.equals(principalRequestValue)) {
ApiKeyAuthenticationToken apiToken = new ApiKeyAuthenticationToken(apiKey, AuthorityUtils.NO_AUTHORITIES);
SecurityContextHolder.getContext().setAuthentication(apiToken);
} else {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setStatus(401);
httpResponse.getWriter().write("Invalid API Key");
return;
}
}
}
chain.doFilter(request, response);
}
}
Here is the filter for jwt (normal user from angular):
public class AuthTokenFilter extends OncePerRequestFilter {
#Autowired
private JwtUtils jwtUtils;
#Autowired
private MyUserDetailsService userDetailsService;
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
try {
String jwt = parseJwt(request);
if (jwt != null && jwtUtils.validateJwtToken(jwt)) {
String username = jwtUtils.getUserNameFromJwtToken(jwt);
MSUserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (Exception e) {
logger.error("Cannot set user authentication: {}", e);
}
filterChain.doFilter(request, response);
}
}
I've created two different controllers, one with prefix /api/users and second /users.
Here is what happen in two different scenarios:
The user login from Angular, get jwt token and process request which end up in the Jwt filter,
this scenarion looking good with no issues as the user is able to process request as long
he is authenticate.
Microservice send a request with api-key to url with /api/users prefix, it ended up on the same
filter the normal user ended which is not correct and without JWT token he is actually
able to proceed to the controller and process the request without going
to the correct filter.
The only solution I have is to have only one filter and process the header
for api-key and jwt but it doesn't seem right.
I've looked online and try to figure out what I'm doing wrong but no clue as of now.
An update on this issue so I hope it will help to the community.
Firstly, I removed the following code and this mainly fix the problem:
// #Override
// public void configure(WebSecurity web) throws Exception {
// web.ignoring().antMatchers("/api/users/**");
// }
The way the solution work as a whole is that the first configuration #Order(1) you
define .antMatcher which means the configuration will work only for urls that match
the prefix.
So now, scenario 1. User from Angular go the the JWT filter only.
scenario 2. API user will lend in the API filter first! But once it's done (After succesfull authentication) it still
continue to the JWT filter but becuase it doesn't have JWT the filter not doing anything.
I would like to avoid to other filter in case of API call but the solution work,
problem solved.
I must say that security in spring boot is the most complex I came across so far from other features.
Because the AuthTokenFilter is instantiated with #Bean, which causes the filter to be added to the ApplicationFilterChain, after the APIKeyAuthFilter is processed, it can also enter the AuthTokenFilter.
I have the following security configuration class in a Spring Cloud Gateway application. This gateway acts as an OAuth2 client handling the user authentication. After a successful authentication, I'd like to redirect to the URL of the single-page application where the user originally came from.
Example
If the user was on http://localhost:8093/profile then this should be the redirect URL.
Currently I only use a hardcoded value which works for testing purposes. Is there a way to get the "original URL" and use it as a redirection URL?
#Configuration
#EnableWebFluxSecurity
public class SecurityConfiguration {
#Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity httpSecurity) {
httpSecurity
.csrf().disable()
.authorizeExchange()
.anyExchange().authenticated()
.and()
.oauth2Login()
// Use original URL here?
.authenticationSuccessHandler(new RedirectServerAuthenticationSuccessHandler("http://localhost:8093"))
.and()
.exceptionHandling().authenticationEntryPoint(new HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED))
.and()
.oauth2ResourceServer().jwt();
return httpSecurity.build();
}
}
You can try below provide the combination to Achieve what you are looking for:
First of all you need to create your Authentication Success Handler:
public class MySimpleUrlAuthenticationSuccessHandler
implements AuthenticationSuccessHandler {
protected Log logger = LogFactory.getLog(this.getClass());
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
#Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException {
handle(request, response, authentication);
clearAuthenticationAttributes(request);
}
Then handle Method implementation:
protected void handle(
HttpServletRequest request,
HttpServletResponse response,
Authentication authentication
) throws IOException {
//This will provide you last URL
String targetUrl = request.getHeader("referer");
if (response.isCommitted()) {
logger.debug(
"Response has already been committed. Unable to redirect to "
+ targetUrl);
return;
}
redirectStrategy.sendRedirect(request, response, targetUrl);
}
Just an FYI:
Note: the HTTP referer is a client-controlled value and can thus be spoofed to something entirely different or even removed. This value should not be used for any critical operation.
Maybe it's too late, but I had the same problem like you. Has Jayesh said, you need to create a class "Authentication Success Handler" to add some logic and redirection after a sucessfull Oauth2 authentication.
But this new class , instead of extending SimpleUrlAuthenticationSucessHandler, must extends SavedRequestAwareAuthenticationSucessHandler and override the method onAuthenticationSucess().
public class OAuth2LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
#Autowired
private UserService userService;
#Autowired
private MessageSource messageSource;
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
CustomOAuth2User oAuth2User = (CustomOAuth2User) authentication.getPrincipal();
User existingUser = userService.findByUsername(oAuth2User.getEmail());
if (existingUser != null) {
// update of user with providerId and authenticationProvider if not already done
log.info(messageSource.getMessage("global.existing-user.oauth2-authenticated",
new Object[] { existingUser }, LocaleContextHolder.getLocale()));
if (existingUser.getAuthenticationProvider() == AuthProvider.LOCAL) {
userService.updateUserFromOAuth2Authentication(oAuth2User, existingUser);
} else if ((!Objects.equals(existingUser.getIdProvider(), oAuth2User.getproviderId())
|| existingUser.getAuthenticationProvider() != oAuth2User.getClientProvider())) {
throw new OAuth2AuthenticationException("a problem occured with Oauth2Authentication!");
}
} else {
// creation of new user
log.info(messageSource.getMessage("global.not-existing-user.oauth2-authenticated",
new Object[] { "createdUser" }, LocaleContextHolder.getLocale()));
userService.saveUserFromOAuth2Authentication(oAuth2User);
}
super.onAuthenticationSuccess(request, response, authentication);
}
}
In your configuration class for security, you just have to call the method successHandler()for Oauth2Login to use your new class "authentication success handler" without of course, using method defaultSucessUrl() , like this
http.oauth2Login()
.loginPage("/app/login")
.userInfoEndpoint()
.userService(oauth2UserService)
.and()
.successHandler(oAuth2LoginSuccessHandler)
;
Sorry for my bad english, i found this solution just after reading this article https://www.baeldung.com/spring-security-redirect-login
I'm trying to implement authentication and authorization using JWT token in SpringBoot REST API.
In my JWTAuthentication class
#Override
protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res,
FilterChain chain, Authentication auth) throws IOException, ServletException {
String token = Jwts.builder().setSubject(((User) auth.getPrincipal()).getUsername())
.claim("roles", ((User) auth.getPrincipal()).getAuthorities())
.setExpiration(new Date(System.currentTimeMillis() + SecurityConstants.EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS512, SecurityConstants.SECRET.getBytes()).compact();
res.addHeader(SecurityConstants.HEADER_STRING, SecurityConstants.TOKEN_PREFIX + token);
chain.doFilter(req, res);
System.out.println("Token:"+token);
}
When I test my code by sending by posting the following message to 127.0.0.1:8080/login URL, I see that authentication is successful.
{"username":"admin", "password":"admin"}
And then Spring calls my JWT Authorization class
#Override
protected void doFilterInternal(
HttpServletRequest req, HttpServletResponse res, FilterChain chain)
throws IOException, ServletException {
String header = req.getHeader(SecurityConstants.HEADER_STRING);
if (header == null || !header.startsWith(SecurityConstants.TOKEN_PREFIX)) {
if (header == null) {
System.out.println("header null");
} else if (!header.startsWith(SecurityConstants.TOKEN_PREFIX)) {
System.out.println("token prefix missing in header");
}
chain.doFilter(req, res);
return;
}
UsernamePasswordAuthenticationToken authentication = getAuthentication(req);
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(req, res);
}
It prints the message: "token prefix missing in header"
Although I add the TOKEN_PREFIX in the successfulAuthentication method, it can not find it in the header in doFilterInternal method.
By the way, my security config is like this:
#EnableWebSecurity(debug = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired private UserDetailsService userDetailsService;
#Autowired private BCryptPasswordEncoder bCryptPasswordEncoder;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors()
.and()
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/admin/**")
.hasRole("ADMIN")
.anyRequest()
.authenticated()
.and()
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
.addFilter(new JWTAuthorizationFilter(authenticationManager()))
// this disables session creation on Spring Security
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(
"/v2/api-docs",
"/configuration/ui",
"/swagger-resources/**",
"/configuration/security",
"/swagger-ui.html",
"/webjars/**");
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}
}
I checked the SpringBoot books but could not find a book that describes the inner details of the security framework. Since I did not understand how the framework works, I could not solve the problems by just looking at the blogs. Is there a book that you can suggest describing the details of SpringBoot Security?
Thanks
You set your token after you successfully authenticated the user to the header of
the Http response:
res.addHeader(SecurityConstants.HEADER_STRING, SecurityConstants.TOKEN_PREFIX + token);
The internal JWT filter (from what I understand in your question is called after yours), looks in the Http headers of the request
String header = req.getHeader(SecurityConstants.HEADER_STRING);
and there they are not present.
In general, the second filter should not be active after you authenticated a user and should just return the JWT token to the client. Any subsequent call of the client should then include the JWT token in the Authorization header using Bearer: YourJWTToken for calling e.g. protected APIs.