2017-07-06 923 views
0

我有單獨的授權服務器和資源服務器。 授權服務器指向一個單獨的數據庫。我已使用CustomUserDetailService作爲用戶相關信息。 我已經使用CustomTokenEnhancer除響應中的令牌外還有其他信息。如何在資源服務器spring-security-oauth2中獲取自定義的UserDetailService對象?

@Configuration 
public class OAuth2Configuration { 


    @Configuration 
    @EnableAuthorizationServer 
    protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter implements EnvironmentAware { 

     private static final String ENV_OAUTH = "authentication.oauth."; 
     private static final String PROP_CLIENTID = "clientid"; 
     private static final String PROP_SECRET = "secret"; 
     private static final String PROP_TOKEN_VALIDITY_SECONDS = "tokenValidityInSeconds"; 

     private RelaxedPropertyResolver propertyResolver; 

     @Autowired 
     private DataSource dataSource; 

     @Autowired 
     private CustomUserDetailService userDetailsService; 

     @Bean 
     public TokenStore tokenStore() { 
      return new CustomTokenStore(dataSource); 
     } 

     @Autowired 
     @Qualifier("authenticationManagerBean") 
     private AuthenticationManager authenticationManager; 

     @Override 
     public void configure(AuthorizationServerEndpointsConfigurer endpoints) 
       throws Exception { 
      endpoints 
        .tokenStore(tokenStore()) 
        .userDetailsService(userDetailsService) 

        .tokenEnhancer(tokenEnhancer()) 
        .accessTokenConverter(accessTokenConverter()) 

        .authenticationManager(authenticationManager); 
     } 

     @Bean 
     public TokenEnhancer tokenEnhancer() { 
      return new CustomTokenEnhancer(); 
     } 

     @Bean 
     public DefaultAccessTokenConverter accessTokenConverter() { 
      return new DefaultAccessTokenConverter(); 
     } 


     @Override 
     public void configure(AuthorizationServerSecurityConfigurer oauthServer) 
       throws Exception { 
      oauthServer 
       .tokenKeyAccess("permitAll()") 
       .checkTokenAccess("isAuthenticated()"); 
     } 
    } 

} 

CustomUserDetailService類別:

@Service 
public class CustomUserDetailService implements UserDetailsService { 


    @Autowired 
    private AccountRepository accountRepository; 

    @Override 
    public UserDetails loadUserByUsername(String username) { 

     Account account = accountRepository.getByEmail(username); 

     if(account == null) { 
      throw new UsernameNotFoundException(username); 
     } 

     return new MyUserPrincipal(account); 

    } 
} 

CustomTokenEnhancer類別:

public class CustomTokenEnhancer implements TokenEnhancer { 

    @Override 
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) { 
     MyUserPrincipal user = (MyUserPrincipal) authentication.getPrincipal(); 
     final Map<String, Object> additionalInfo = new HashMap<>(); 

     additionalInfo.put("user_information", user.getAccount()); 

     ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo); 

     return accessToken; 
    } 

} 

請求/響應

http://localhost:9191/authserver/oauth/token 


{ 
    "access_token": "fddb571e-224e-4cd7-974e-65104dd24b41", 
    "token_type": "bearer", 
    "refresh_token": "eb412b00-9e4e-4d6c-86d8-324d999b5f08", 
    "expires_in": 100, 
    "scope": "read write", 
    "account_information": { 
     "id": 14, 
     "firstname": "name", 
     "lastname": "lastname", 

    } 
} 

在資源服務器端,我已經使用RemoteTokenSerice噸o驗證用戶提供的令牌是否有效。

@Configuration 
@EnableResourceServer 
public class OAuthResourceConfig extends ResourceServerConfigurerAdapter { 

    private TokenExtractor tokenExtractor = new BearerTokenExtractor(); 

    @Override 
    public void configure(HttpSecurity http) throws Exception { 
     http.addFilterAfter(new OncePerRequestFilter() { 
      @Override 
      protected void doFilterInternal(HttpServletRequest request, 
        HttpServletResponse response, FilterChain filterChain) 
        throws ServletException, IOException { 
       if (tokenExtractor.extract(request) == null) { 
        SecurityContextHolder.clearContext(); 
       } 
       filterChain.doFilter(request, response); 
      } 
     }, AbstractPreAuthenticatedProcessingFilter.class); 
     http.csrf().disable(); 
     http.authorizeRequests().anyRequest().authenticated(); 
    } 

    @Bean 
    public AccessTokenConverter accessTokenConverter() { 
     return new DefaultAccessTokenConverter(); 
    } 

    @Bean 
    @Primary 
    public RemoteTokenServices remoteTokenServices(final @Value("${auth.server.url}") String checkTokenUrl, 
      final @Value("${auth.server.clientId}") String clientId, 
      final @Value("${auth.server.clientsecret}") String clientSecret) { 


     final RemoteTokenServices remoteTokenServices = new RemoteTokenServices(); 
     remoteTokenServices.setCheckTokenEndpointUrl(checkTokenUrl+"?name=value"); 
     remoteTokenServices.setClientId(clientId); 
     remoteTokenServices.setClientSecret(clientSecret); 
     remoteTokenServices.setAccessTokenConverter(accessTokenConverter()); 
     return remoteTokenServices; 
    } 

    } 

因此它工作正常,當我向令牌請求資源服務器時,如果令牌有效,它會處理請求。我的問題是我想要在資源服務器中獲得Account對象。我試着用下面:

Account account = (Account)SecurityContextHolder.getContext().getAuthentication().getPrincipal() 

但它給字符串,而不是完整的用戶定義的對象,因此它拋出的exception.How獲得帳戶對象在資源服務器中的任何控制器?

{ 
    "timestamp": 1499334657703, 
    "status": 500, 
    "error": "Internal Server Error", 
    "exception": "java.lang.ClassCastException", 
    "message": "java.lang.String cannot be cast to Account", 
    "path": "/secure" 
    } 

我試着用link但有可能注入兩個令牌服務,RemoteTokenService和CustomUserInfoTokenServices兩者兼而有之?

此外,我認爲在這裏春讓資源服務器內部呼叫到授權服務器(http://localhost:9191/authserver/oauth/check_token?token=d8dae984-7bd8-4aab-9990-a2c916dfe667)驗證令牌。

有沒有什麼辦法可以在控制器中獲取這些信息,而無需再次調用此端點。

響應:

{ 
    "exp": 1499333294, 
    "account_information": { 
     "accountid": 14, 
     "firstname": "fname", 
     "lastname": "lname", 

    }, 
    "user_name": "[email protected]", 
    "client_id": "clientId", 
    "scope": [ 
     "read", 
     "write" 
    ] 
} 

回答

0

我已重寫下面的方法和增加了一些邏輯。

public class CustomAccessTokenConverter extends DefaultAccessTokenConverter{ 

    private UserAuthenticationConverter userTokenConverter = new DefaultUserAuthenticationConverter(); 

    @Override 
    public OAuth2Authentication extractAuthentication(Map<String, ?> map) { 
     Map<String, String> parameters = new HashMap<String, String>(); 
     @SuppressWarnings("unchecked") 
     Set<String> scope = new LinkedHashSet<String>(map.containsKey(SCOPE) ? (Collection<String>) map.get(SCOPE) 
       : Collections.<String>emptySet()); 
     Authentication user = userTokenConverter.extractAuthentication(map); 
     String clientId = (String) map.get(CLIENT_ID); 
     parameters.put(CLIENT_ID, clientId); 
     parameters.put("account_information", String.valueOf((((Map) map.get("account_information")).get("accountid")))); 
     @SuppressWarnings("unchecked") 
     Set<String> resourceIds = new LinkedHashSet<String>(map.containsKey(AUD) ? (Collection<String>) map.get(AUD) 
       : Collections.<String>emptySet()); 

     Map<String, Serializable> extensions = new HashMap<String, Serializable>(); 
     extensions.put("account_information", (HashMap) map.get("account_information")); 

     OAuth2Request request = new OAuth2Request(parameters, clientId, null, true, scope, resourceIds, null, null, 
       extensions); 
     return new OAuth2Authentication(request, user); 
    } 

} 

資源服務器類現在

@Bean 
    public AccessTokenConverter accessTokenConverter() { 
     //return new DefaultAccessTokenConverter(); 
     return new CustomAccessTokenConverter(); 
    } 

    @Bean 
    @Primary 
    public RemoteTokenServices remoteTokenServices(final @Value("${auth.server.url}") String checkTokenUrl, 
      final @Value("${auth.server.clientId}") String clientId, 
      final @Value("${auth.server.clientsecret}") String clientSecret) { 


     final RemoteTokenServices remoteTokenServices = new RemoteTokenServices(); 
     remoteTokenServices.setCheckTokenEndpointUrl(checkTokenUrl+"?name=value"); 
     remoteTokenServices.setClientId(clientId); 
     remoteTokenServices.setClientSecret(clientSecret); 
     remoteTokenServices.setAccessTokenConverter(accessTokenConverter()); 
     return remoteTokenServices; 
    } 

我可以在控制器的其他信息。

OAuth2Authentication authentication = (OAuth2Authentication)SecurityContextHolder.getContext().getAuthentication(); 

     Map<String, Serializable> map = authentication.getOAuth2Request().getExtensions(); 
相關問題