2017-07-06 2 views
0

Ich habe separaten Autorisierungsserver und Ressourcenserver. Der Autorisierungsserver verweist auf eine separate Datenbank. Ich habe CustomUserDetailService für benutzerbezogene Informationen verwendet. Ich habe CustomTokenEnhancer verwendet, um zusätzliche Informationen neben dem Token in der Antwort zu haben.Wie benutzerdefinierte UserDetailService-Objekt in Resource Server in Spring-Security-oauth2 erhalten?

@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 Klasse:

@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 Klasse:

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; 
    } 

} 

Request/Response

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", 

    } 
} 

Auf Seite Ressource-Server habe ich RemoteTokenSerice t verwendet o Überprüfen Sie, ob das vom Benutzer angegebene Token gültig ist oder nicht.

@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; 
    } 

    } 

So funktioniert Es ist richtig, und wenn ich einen Antrag stellen Server mit Token Ressourcen, verarbeitet es die Anfrage, ob das Token gültig ist. Meine Frage ist, ich möchte Account-Objekt in Ressourcenserver erhalten. Ich habe versucht, mit unter:

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

Aber es gibt String und nicht das komplette Benutzerobjekt definieren und somit wirft es die exception.How Konto Objekt in jedem Controller in Ressource-Server zu bekommen?

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

Ich habe versucht, mit link aber ist es möglich, beide zwei Token Services, RemoteTokenService und CustomUserInfoTokenServices zu injizieren?

Auch ich denke, hier Frühjahr macht internen Aufruf von Resource Server zu Authorization Server (http://localhost:9191/authserver/oauth/check_token?token=d8dae984-7bd8-4aab-9990-a2c916dfe667), um das Token zu validieren.

Gibt es eine Möglichkeit, diese Informationen im Controller abrufen zu können, ohne diesen Endpunkt erneut aufzurufen.

Antwort:

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

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

Antwort

0

Ich habe unten Methode überschrieben und einige Logik hinzugefügt.

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); 
    } 

} 

Ressourcenserverklasse

@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; 
    } 

Jetzt kann ich zusätzliche Informationen in der Steuerung erhalten.

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

     Map<String, Serializable> map = authentication.getOAuth2Request().getExtensions(); 
Verwandte Themen