Mejmo
Mejmo

Reputation: 2593

How to get JWT token in SecurityContextHolder in Spring Boot OAuth2?

I have a resource server which is receiving requests with valid Bearer token. I can either use @AuthenticationPrincipal Jwt token for all requests where I need to get claims from the token or I should be able to get the user information from SecurityContextHolder right? I would like to get it from the context holder. I would assume I need to define jwt converter in my SecurityConfig? I cannot find any information on the recommended approach.

The code from here works with some legacy versions of spring security... I am using the newest spring boot with Spring security 5.4.2

@Configuration
@EnableWebSecurity
@Order(1)
public class JwtSecurityConfig extends WebSecurityConfigurerAdapter {

    @Value("${spring.security.oauth2.resourceserver.jwt.jwk-set-uri}")
    private String jwkSetUri;

    protected void configure(HttpSecurity http) throws Exception {
        http
                .httpBasic().disable()
                .formLogin(AbstractHttpConfigurer::disable)
                .csrf(AbstractHttpConfigurer::disable)
                .authorizeRequests(authorize -> authorize
                        .mvcMatchers(HttpMethod.GET, "/test/**").authenticated()
                        .mvcMatchers(HttpMethod.POST, "/test/**").authenticated()
                )
                .oauth2ResourceServer().jwt().jwtAuthenticationConverter(jwtAuthenticationConverter());
    }

    private JwtAuthenticationConverter jwtAuthenticationConverter() {
        JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
        jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("entGrps");
        jwtGrantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");
        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
        return jwtAuthenticationConverter;
    }

    @Bean
    public JwtDecoder jwtDecoder() {
        return NimbusJwtDecoder.withJwkSetUri(this.jwkSetUri).build();
    }
}

Upvotes: 2

Views: 25791

Answers (3)

emyasa
emyasa

Reputation: 86

If our only concern is to retrieve the token from the header, the simplest solution I came up with is to use the DefaultBearerTokenResolver:

public class CheckAuthTokenFilter extends GenericFilterBean {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) {
        String token = new DefaultBearerTokenResolver().resolve((HttpServletRequest) servletRequest);
    }
}

Upvotes: 0

swapper9
swapper9

Reputation: 43

If you are plan to use spring-security-oauth2-resource-server dependency, I think would be better to use @AuthenticationPrincipal Jwt token to get token's claims.

That's simplier and less boilerplate code.

But that's up to you, Imranmadbar's solution is also working)

Upvotes: 2

Imranmadbar
Imranmadbar

Reputation: 5470

If you want information from SecurityContextHolder, you have to keep it on there.

Here is the easiest solution for this:

  1. Get Auth Token from the request, where your current log user info present.
  2. Extract log user name from jwt using some Util method.
  3. Get the user details from the Database using this user name.
  4. Finally Set this User info into the Spring Security context holder.

And you have to do this every Request Using an HTTP Request Filter (OncePerRequestFilter).

Like:

        import java.io.IOException;

        import javax.servlet.FilterChain;
        import javax.servlet.ServletException;
        import javax.servlet.http.HttpServletRequest;
        import javax.servlet.http.HttpServletResponse;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
        import org.springframework.security.core.context.SecurityContextHolder;
        import org.springframework.security.core.userdetails.UserDetails;
        import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
        import org.springframework.stereotype.Component;
        import org.springframework.web.filter.OncePerRequestFilter;
        import com.madbarsoft.config.MyUserDetailsService;
        import com.madbarsoft.utility.JwtUitl;

        @Component
        public class JwtRequestFilter extends OncePerRequestFilter {    
                    
                    @Autowired
                    private JwtUitl jwtUitl;
                    
                    @Autowired
                    private MyUserDetailsService userDetailsService; 

                    @Override
                    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chin)
                            throws ServletException, IOException {
                        
                        final String authorizationHeader = request.getHeader("Authorization");
                        System.out.println("Authorization Header #:"+authorizationHeader);
                        
                        String userName = null;
                        String jwtStr = null;
                        
                        if(authorizationHeader != null && authorizationHeader.startsWith("Bearer ")){
                            jwtStr = authorizationHeader.substring(7);
                            userName = jwtUitl.extractUserName(jwtStr);
                            System.out.println("Form JWT userName: "+userName);
                        }
                        System.out.println("In Filter Before set #: "+SecurityContextHolder.getContext().getAuthentication());
                        if(userName != null && SecurityContextHolder.getContext().getAuthentication() == null){
                            UserDetails userDetails = this.userDetailsService.loadUserByUsername(userName);
                            if(jwtUitl.validateToken(jwtStr, userDetails)){
                                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                                        userDetails, null, userDetails.getAuthorities());
                                usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
                            }
                            System.out.println("In Filter After Set #: "+SecurityContextHolder.getContext().getAuthentication());
                        }
                        chin.doFilter(request, response);
                    
                    }
                }

Now you can access user info from anywhere in the Entire Project.

(It's a working Project, You can take some info from gitLink here.)

Upvotes: 0

Related Questions