Spring Boot Oauth2资源服务器UserDetailsS​​ervice

问题描述

尝试让UserDetailsS​​ervice适用于我设置的oauth2资源服务器。我能够成功验证jwt,但似乎没有任何办法让它调用loadUserByUsername方法。最初使用SAML并可以正常工作,但是现在我切换到了Oauth2,但无法正常工作。

     @Service
     public class OauthUsersDetailsServiceImpl implements UserDetailsService{
         @Override
         public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
             //some user loading junk here - this is never called
         }
     }
     @Configuration
        @EnableGlobalMethodSecurity(prePostEnabled = true)
        @EnableWebSecurity
         public class SecurityConfig extends WebSecurityConfigurerAdapter {
            
            @Override
            protected void configure(HttpSecurity http) throws Exception
            {
                //test key for Now
                SecretKeySpec key = new SecretKeySpec("private key0000000000000000000000000000000".getBytes(),"HMACSHA256");
                

                http
                    .authorizeRequests()
                    .antMatchers(/*some endpoints im excluding from auth - this all works*/)
                    .permitAll().and()
                    .authorizeRequests()
                    .anyRequest().authenticated().and()
                    .oauth2ResourceServer().jwt().decoder(NimbusJwtDecoder.withSecretKey(key).build());
            }
         }

我在Google上发现我可以使用@service将类注册为Bean,而spring只会选择它,但是它不起作用。我也尝试通过AuthenticationManagerBuilder添加它,但这也不起作用。我的猜测是,它的jwt端具有其自己的UserDetailsS​​ervice,该UserDetailsS​​ervice已实现,并且优先于我的。也就是说,什么是让我的呼叫正确的方法,还是在身份验证完成并覆盖Principal对象之后以某种方式手动调用用户加载逻辑更好?我需要在调用端点之前进行此操作,以便PreAuthorize可以检查UserDetailsS​​ervice加载的角色。

解决方法

弄清楚了。希望这将对遇到相同问题的任何人有所帮助。我必须在链中添加一个自定义过滤器,以调用我的用户详细信息服务并覆盖上下文:

public class Oauth2AuthorizationFilter extends GenericFilterBean {

        @Autowired
        private OauthUsersDetailsServiceImpl oauthUsersDetailsServiceImpl;
      
      public Oauth2AuthorizationFilter (OauthUsersDetailsServiceImpl userDetailsService) {
        this.oauthUsersDetailsServiceImpl = userDetailsService;
      }
      
      
      @Override
      public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)
          throws IOException,ServletException {

        SecurityContext context = SecurityContextHolder.getContext();
        if(context.getAuthentication() != null && !(context.getAuthentication().getPrincipal() instanceof Users)) {
          
          UserDetails user = oauthUsersDetailsServiceImpl.loadUserByUsername(((Jwt)context.getAuthentication().getPrincipal()).getClaimAsString("user_name")); 
          UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(user,null,user.getAuthorities());
          context.setAuthentication(authentication);
        }
        
        chain.doFilter(request,response);
      }

    }
@Override
        protected void configure(HttpSecurity http) throws Exception
        {
            //test key for now
            SecretKeySpec key = new SecretKeySpec("private key0000000000000000000000000000000".getBytes(),"HMACSHA256");
            
            http.authorizeRequests().antMatchers(/*bunch of junk...*/).permitAll().and().authorizeRequests().anyRequest().authenticated().and()
                .oauth2ResourceServer().jwt().decoder(NimbusJwtDecoder.withSecretKey(key).build());
            
            http.addFilterAfter(jwtAuthTokenFilterBean(),SwitchUserFilter.class);

        }

那终于做到了我所需要的

,

您需要注册UserDetailsS​​ervice实现,然后DaoAuthenticationProvider会使用该实现

// userDetailsService bean
@Autowired
private OauthUsersDetailsServiceImpl oauthUsersDetailsServiceImpl;

// 
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(oauthUsersDetailsServiceImpl);
}