Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
533 views
in Technique[技术] by (71.8m points)

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();
    }
}
question from:https://stackoverflow.com/questions/65897449/how-to-get-jwt-token-in-securitycontextholder-in-spring-boot-oauth2

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...