Могу ли я включать информацию пользователя при выдаче токена доступа?

Я видел в некоторых реализациях oauth2 дополнительную информацию об ответе, возвращаемом сервером авторизации, когда он выдает токены доступа. Мне интересно, есть ли способ сделать это, используя spring -security-oauth2. Я хотел бы включить некоторые пользовательские полномочия в ответ на токен доступа, чтобы моим потребляющим приложениям не нужно было управлять полномочиями пользователей, но все равно можно настроить пользователя на свои собственные контексты безопасности и применить любые свои собственные spring - проверки безопасности.

  • Как мне получить эту информацию об ответе маркера доступа?
  • Как перехватить эту информацию на стороне клиента oauth2 и установить ее в контексте безопасности?

Я полагаю, что другой вариант - использовать токены JWT и делиться соответствующей информацией с клиентскими приложениями, чтобы они могли разобрать пользователь/полномочия из токена и установить его в контексте. Это делает меня более неудобным, так как я предпочел бы контролировать, какие клиентские приложения могут иметь доступ к этой информации (только доверенные приложения), и AFAIK только сервер авторизации и сервер ресурсов должны знать, как разбирать токены JWT.

Ответы

Ответ 1

Вам нужно будет реализовать пользовательский TokenEnhancer, например:

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

}

и добавьте его в свой AuthorizationServerConfigurerAdapter как bean с соответствующими сеттерами

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

}

затем в контроллере (например)

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

}

Я использую JDBC TokenStore, поэтому мои "некоторые автоувеличиваемые материалы здесь" соответствуют некоторым @Autowired Datasource, PasswordEncoder и что нет.

Надеюсь, это помогло!

Ответ 2

Если вы используете Spring JwtAccessTokenConverter или DefaultAccessTokenConverter, вы можете добавить свой собственный CustomTokenEnhancer (см. первый ответ) и применить его с помощью TokenEnhancerChain, как это:

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

Другим решением является создание пользовательского TokenConverter, который расширяет Spring JwtAccessTokenConverter и переопределяет метод enhance() с вашими пользовательскими требованиями.

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

И затем:

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

    endpoints.tokenStore(tokenStore())
            .tokenEnhancer(customTokenEnhancer())
            .authenticationManager(authenticationManager);
}

@Bean public CustomTokenConverter customTokenEnhancer() {
    return new CustomTokenConverter();
}

Ответ 3

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

}

Ответ 4

Вместе с:

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

Вы должны включить

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

и добавьте все в конфигурацию конечных точек:

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

        endpoints
                .tokenStore(tokenStore)
                .tokenEnhancer(tokenEnhancer())
                .accessTokenConverter(accessTokenConverter())
                .authorizationCodeServices(codeServices)
                .authenticationManager(authenticationManager)
        ;
    }

Без этого ваш CustomTokenEnhancer не будет работать.

Ответ 5

  1. создать файл класса 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. вставьте ниже написанный код в 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. импортировать соответствующие библиотеки после вставки вышеуказанных кодов

выходной ответ Custom Token Enhancer.. нажмите здесь

Ответ 6

Я решаю эту проблему, когда исключен UserDetailsServiceAutoConfiguration. Как это. Может быть, будет полезен на серверах ресурсов OAuth2.

@SpringBootApplication(exclude = [UserDetailsServiceAutoConfiguration::class])
class Application

fun main(args: Array<String>) {
    runApplication<Application>(*args)
}