can I include user information while issuing an access token?

后端 未结 6 641
無奈伤痛
無奈伤痛 2020-11-28 03:58

I have seen in some oauth2 implementations additional information on the response returned by the authorization server when it issues access tokens. I\'m wondering if there

相关标签:
6条回答
  • 2020-11-28 04:24

    Together with:

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

    You have to include

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

    and add everything to endpoints config:

    @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    
            endpoints
                    .tokenStore(tokenStore)
                    .tokenEnhancer(tokenEnhancer())
                    .accessTokenConverter(accessTokenConverter())
                    .authorizationCodeServices(codeServices)
                    .authenticationManager(authenticationManager)
            ;
        }
    

    Without it, your CustomTokenEnhancer will not work.

    0 讨论(0)
  • 2020-11-28 04:27

    I solve this problem when excluded UserDetailsServiceAutoConfiguration. Like this. Maybe wiil be helpful in OAuth2 resource servers.

    @SpringBootApplication(exclude = [UserDetailsServiceAutoConfiguration::class])
    class Application
    
    fun main(args: Array<String>) {
        runApplication<Application>(*args)
    }
    
    0 讨论(0)
  • 2020-11-28 04:28

    You will need to implement a custom TokenEnhancer like so:

    public class CustomTokenEnhancer implements TokenEnhancer {
    
        @Override
        public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
            User user = (User) authentication.getPrincipal();
            final Map<String, Object> additionalInfo = new HashMap<>();
    
            additionalInfo.put("customInfo", "some_stuff_here");
            additionalInfo.put("authorities", user.getAuthorities());
    
            ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
    
            return accessToken;
        }
    
    }
    

    and add it to your AuthorizationServerConfigurerAdapter as a bean with the corresponding setters

    @Configuration
    @EnableAuthorizationServer
    protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
    
        // Some autowired stuff here
    
        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            // @formatter:off
            endpoints
                // ...
                .tokenEnhancer(tokenEnhancer());
            // @formatter:on
        }
    
        @Bean
        @Primary
        public AuthorizationServerTokenServices tokenServices() {
            DefaultTokenServices tokenServices = new DefaultTokenServices();
            // ...
            tokenServices.setTokenEnhancer(tokenEnhancer());
            return tokenServices;
        }
    
        // Some @Bean here like tokenStore
    
        @Bean
        public TokenEnhancer tokenEnhancer() {
            return new CustomTokenEnhancer();
        }
    
    }
    

    then in a controller (for example)

    @RestController
    public class MyController {
    
        @Autowired
        private AuthorizationServerTokenServices tokenServices;
    
        @RequestMapping(value = "/getSomething", method = RequestMethod.GET)
        public String getSection(OAuth2Authentication authentication) {
            Map<String, Object> additionalInfo = tokenServices.getAccessToken(authentication).getAdditionalInformation();
    
            String customInfo = (String) additionalInfo.get("customInfo");
            Collection<? extends GrantedAuthority> authorities = (Collection<? extends GrantedAuthority>) additionalInfo.get("authorities");
    
            // Play with authorities
    
            return customInfo;
        }
    
    }
    

    I'm personnaly using a JDBC TokenStore so my "Some autowired stuff here" are corresponding to some @Autowired Datasource, PasswordEncoder and what not.

    Hope this helped!

    0 讨论(0)
  • 2020-11-28 04:43
    1. create a class file CustomTokenEnhancer
    @Component
    public class CustomTokenConverter extends JwtAccessTokenConverter {
    
    
        @Override
        public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
    
            final Map<String, Object> additionalInfo = new HashMap<>();
            additionalInfo.put("customized", "true");
            User user = (User) authentication.getPrincipal();
            additionalInfo.put("role", user.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()));
            ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
    
            return super.enhance(accessToken, authentication);
        }
    }
    
    1. paste below written code in AuthorizationServerConfig
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
        enhancerChain.setTokenEnhancers(Arrays.asList(customTokenEnhancer(),accessTokenConverter()));
    
        endpoints
            .tokenStore(tokenStore())
            .tokenEnhancer(customTokenEnhancer())
            .authenticationManager(authenticationManager);
    }
    
    @Bean
    protected JwtAccessTokenConverter jwtTokenEnhancer() {
        JwtAccessTokenConverter converter=  new JwtAccessTokenConverter();
        converter.setSigningKey("my_signing_key");
    
        return converter;
    }
    
    @Bean
    public CustomTokenConverter customTokenEnhancer() {
        return new CustomTokenConverter();
    }
    
    @Bean
    public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }
    
    1. import appropriate libraries after paste the above codes

    output response of Custom Token Enhancer..click here

    0 讨论(0)
  • 2020-11-28 04:44

    If you are using Spring's JwtAccessTokenConverter or DefaultAccessTokenConverter you can add your custom CustomTokenEnhancer (see first response) and apply it using a TokenEnhancerChain like this:

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    
        TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
        enhancerChain.setTokenEnhancers(Arrays.asList(customTokenEnhancer(), accessTokenConverter()));
    
        endpoints.tokenStore(tokenStore())
                .tokenEnhancer(enhancerChain)
                .authenticationManager(authenticationManager);
    }
    
    @Bean
    protected JwtAccessTokenConverter jwtTokenEnhancer() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("my_signing_key");
        return converter;
    }
    
    @Bean public TokenEnhancer customTokenEnhancer() {
        return new CustomTokenEnhancer();
    }
    

    Another solution is to create a custom TokenConverter that extends Spring's JwtAccessTokenConverter and override the enhance() method with your custom claims.

    public class CustomTokenConverter extends JwtAccessTokenConverter {
    
    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
    
        final Map<String, Object> additionalInfo = new HashMap<>();
        additionalInfo.put("customized", "true");
        User user = (User) authentication.getPrincipal();
        additionalInfo.put("isAdmin", user.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()).contains("BASF_ADMIN"));
        ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
    
        return super.enhance(accessToken, authentication);
        }
    } 
    

    And then:

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    
        endpoints.tokenStore(tokenStore())
                .tokenEnhancer(customTokenEnhancer())
                .authenticationManager(authenticationManager);
    }
    
    @Bean public CustomTokenConverter customTokenEnhancer() {
        return new CustomTokenConverter();
    }
    
    0 讨论(0)
  • 2020-11-28 04:45

    package com.security;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import org.springframework.security.core.userdetails.User;
    import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
    import org.springframework.security.oauth2.common.OAuth2AccessToken;
    import org.springframework.security.oauth2.provider.OAuth2Authentication;
    import org.springframework.security.oauth2.provider.token.TokenEnhancer;
    import org.springframework.stereotype.Component;
    
    @Component
    public class CustomTokenEnhancer implements TokenEnhancer {
    
    	@Override
    	public OAuth2AccessToken enhance(OAuth2AccessToken accessToken,
    			OAuth2Authentication authentication) {
    		// TODO Auto-generated method stub
    		User user = (User) authentication.getPrincipal();
            final Map<String, Object> additionalInfo = new HashMap<>();
    
            additionalInfo.put("customInfo", "some_stuff_here");
            additionalInfo.put("authorities", user.getAuthorities());
    
            ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
    
            return accessToken;
    	}
    
    }

    Following is the xml configuration:

    <bean id="tokenEnhancer" class="com.security.CustomTokenEnhancer" />
    
    <!-- Used to create token and and every thing about them except for their persistence that is reposibility of TokenStore (Given here is a default implementation) -->
    <bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
      <property name="tokenStore" ref="tokenStore" />
      <property name="accessTokenValiditySeconds" value="30000000"></property>
      <property name="refreshTokenValiditySeconds" value="300000000"></property>
      <property name="supportRefreshToken" value="true"></property>
      <property name="clientDetailsService" ref="clientDetails"></property>
      <property name="tokenEnhancer" ref="tokenEnhancer" />
    </bean>

    That's how I was able to add extra information to the Token.

    0 讨论(0)
提交回复
热议问题