web-dev-qa-db-ja.com

Spring OAuth2-トークンストアでアクセストークンを手動で作成する

自分で(通常のプロセスではなく)アクセストークンを作成したい状況があります。私はこのようなものを考え出しました:

@Inject
private DefaultTokenServices defaultTokenServices;

... 

OAuth2Authentication auth = xxx;
OAuth2AccessToken  token = defaultTokenServices.createAccessToken(auth);

唯一の問題は、OAuth2Authenticationの作成方法がわからないことです(私のコードではxxxの部分)。ユーザーとクライアントの情報があり、このトークンを付与する機関を知っています。

14
checklist

ここでは、使用しているフローに基づいてユースケースが若干異なる場合があります。これは、パスワード付与フローで機能します。トークンストア、トークンエンハンサーなどのカスタムクラスがいくつかあります。しかし、それは実際には、独自のニーズに合わせて変更されたスプリングクラスの拡張バージョンにすぎません。

        HashMap<String, String> authorizationParameters = new HashMap<String, String>();
        authorizationParameters.put("scope", "read");
        authorizationParameters.put("username", "mobile_client");
        authorizationParameters.put("client_id", "mobile-client");
        authorizationParameters.put("grant", "password");

        DefaultAuthorizationRequest authorizationRequest = new DefaultAuthorizationRequest(authorizationParameters);
        authorizationRequest.setApproved(true);

        Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
        authorities.add(new SimpleGrantedAuthority("ROLE_UNTRUSTED_CLIENT"));
        authorizationRequest.setAuthorities(authorities);

        HashSet<String> resourceIds = new HashSet<String>();
        resourceIds.add("mobile-public");
        authorizationRequest.setResourceIds(resourceIds);

        // Create principal and auth token
        User userPrincipal = new User(user.getUserID(), "", true, true, true, true, authorities);

        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userPrincipal, null, authorities) ;

        OAuth2Authentication authenticationRequest = new OAuth2Authentication(authorizationRequest, authenticationToken);
        authenticationRequest.setAuthenticated(true);

        CustomTokenStore tokenStore = new CustomTokenStore();

        // Token Enhancer
        CustomTokenEnhancer tokenEnhancer = new CustomTokenEnhancer(user.getUserID());

        CustomTokenServices tokenServices = new CustomTokenServices();
        tokenServices.setTokenEnhancer(tokenEnhancer);
        tokenServices.setSupportRefreshToken(true);
        tokenServices.setTokenStore(tokenStore);

        OAuth2AccessToken accessToken = tokenServices.createAccessTokenForUser(authenticationRequest, user);
18
Michael

TokenEndpointインターフェースを使用してトークンを生成する方法を次に示します(RESTサービスを公開するために使用):

@Inject
private TokenEndpoint tokenEndpoint;

public ResponseEntity<?> getToken(Principal principal) {

        HashMap<String, String> parameters = new HashMap<String, String>();
        parameters.put("client_id", "appid");
        parameters.put("client_secret", "myOAuthSecret");
        parameters.put("grant_type", "password");
        parameters.put("password", myUser.getPassword());
        parameters.put("scope", "read write");
        parameters.put("username", myUser.getLogin());

        return tokenEndpoint.getAccessToken(principal, parameters);
}
13
Mop So

別の方法として、OAuth2 Accesss Tokenを手動で生成するには、TokenServiceのインスタンスを使用できます

@Autowired
private AuthorizationServerEndpointsConfiguration configuration;

@Override
public String generateOAuth2AccessToken(User user, List<Role> roles, List<String> scopes) {

    Map<String, String> requestParameters = new HashMap<String, String>();
    Map<String, Serializable> extensionProperties = new HashMap<String, Serializable>();

    boolean approved = true;
    Set<String> responseTypes = new HashSet<String>();
    responseTypes.add("code");

    // Authorities
    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    for(Role role: roles)
        authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getName()));

    OAuth2Request oauth2Request = new OAuth2Request(requestParameters, "clientIdTest", authorities, approved, new HashSet<String>(scopes), new HashSet<String>(Arrays.asList("resourceIdTest")), null, responseTypes, extensionProperties);

    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUsername(), "N/A", authorities);

    OAuth2Authentication auth = new OAuth2Authentication(oauth2Request, authenticationToken);

    AuthorizationServerTokenServices tokenService = configuration.getEndpointsConfigurer().getTokenServices();

    OAuth2AccessToken token = tokenService.createAccessToken(auth);

    return token.getValue();
}
5
Huy Ta

私のソリューションはモップソーの答えに基づいていますが、代わりに以下を使用します:

_return tokenEndpoint.getAccessToken(principal, parameters);
_

私が使用した:

_tokenEndpoint.postAccessToken(principal, parameters);
_

どうして? tokenEndpoint.getAccessToken(principal, parameters)を使用すると、HttpRequestMethodNotSupportedExceptionメソッドで呼び出されていないため、エンドポイントによってGETがスローされます。少なくとも、これは_spring-security-oauth2-2.0.13.RELEASE_で私に起こったことです

_public OAuth2AccessToken getAccessToken() throws HttpRequestMethodNotSupportedException {
    HashMap<String, String> parameters = new HashMap<>();
    parameters.put("client_id", CLIENT_ID);
    parameters.put("client_secret", CLIENT_SECRET);
    parameters.put("grant_type", "client_credentials");

    ClientDetails clientDetails = clientDetailsStore.get(CLIENT_ID);

    // Create principal and auth token
    User userPrincipal = new User(CLIENT_ID, CLIENT_SECRET, true, true, true, true, clientDetails.getAuthorities());

    UsernamePasswordAuthenticationToken principal = new UsernamePasswordAuthenticationToken(userPrincipal, CLIENT_SECRET,
            clientDetails.getAuthorities());

    ResponseEntity<OAuth2AccessToken> accessToken = tokenEndpoint.postAccessToken(principal, parameters);

    return accessToken.getBody();
}
_
2
flags

これは私のために働きました:

@Override public OAuth2AccessToken getToken(String username, String password) {
    HashMap<String, String> parameters = new HashMap<String, String>();
    parameters.put("client_id", clientid);
    parameters.put("grant_type", "password");
    parameters.put("password", username);
    parameters.put("scope", scope);
    parameters.put("username", password);

    AuthorizationRequest authorizationRequest = defaultOAuth2RequestFactory.createAuthorizationRequest(parameters);
    authorizationRequest.setApproved(true);

    OAuth2Request oauth2Request = defaultOAuth2RequestFactory.createOAuth2Request(authorizationRequest);
    // Create principal and auth token
    final UsernamePasswordAuthenticationToken loginToken = new UsernamePasswordAuthenticationToken(
            username, password);
    Authentication authentication = authenticationManager.authenticate(loginToken);

    OAuth2Authentication authenticationRequest = new OAuth2Authentication(oauth2Request, authentication);
    authenticationRequest.setAuthenticated(true);

    OAuth2AccessToken accessToken = tokenServices.createAccessToken(authenticationRequest);

    return accessToken;
}

Oauth2Configuration:

@Bean
    DefaultOAuth2RequestFactory defaultOAuth2RequestFactory() {
    return new DefaultOAuth2RequestFactory(clientDetailsService);
}

Oauth2Configurationの残りの部分は、記事のようになります。

http://stytex.de/blog/2016/02/01/spring-cloud-security-with-oauth2/

1
Laci

問題

ここにリストされているすべての実装に問題があったため、ようやくステートレスサーバー、oauth2、およびgoogle socialを使用して独自に実装できました。チュートリアルの最後の欠けている部分 here

私の問題は、google oauthを実行した後、10秒の持続時間トークンを長期間トークンに交換する必要があることです。そのためには、JWTトークンを生成し、それを自分で生成した実際のアクセストークンと交換する必要があります。

実装

@Service
class SocialTokenVerificationService {

    @Autowired
    private lateinit var jwsTokenService: JWSTokenService
    @Autowired
    private lateinit var clientDetailsService: ClientDetailsService
    @Autowired
    private lateinit var userService: UserService
    @Autowired
    private lateinit var tokenServices: DefaultTokenServices
    @Autowired
    private lateinit var tokenRequestFactory: OAuth2RequestFactory

    fun verifyToken(token: String): OAuth2AccessToken? {
        val claimSet = jwsTokenService.parseToken(token)
        val userDetails = userService.loadUserByUsername(claimSet.subject)

        val client = clientDetailsService.loadClientByClientId(DEFAULT_SERVER_CLIENT)
        val parameters = HashMap<String, String>()
        val authentication = UsernamePasswordAuthenticationToken(userDetails, null, userDetails.authorities)
        return tokenServices.createAccessToken(OAuth2Authentication(
                tokenRequestFactory.createOAuth2Request(client, TokenRequest(parameters, client.clientId, listOf("read", "write"), "password")),
                authentication
        ))
    }
}
  • JWSTokenService:google oauthとmineの間の交換トークンをエンコードおよびデコードする自己実装クラスです。
  • ClientDetailsService:認可サーバーの一部として宣言されたBean。私のデータベースからのもの

    オーバーライドfun configure(clients:ClientDetailsS​​erviceConfigurer){clients.jdbc(datasource)}

  • UserService:データベースからユーザーを取得するためにUserDetailsServiceを拡張するユーザーサービス

  • DefaultTokenServices:次のようにプライマリBeanとして実装されます

    @Bean
    @Primary
    fun tokenServices(): DefaultTokenServices {
        val defaultTokenServices = DefaultTokenServices()
        defaultTokenServices.setTokenStore(tokenStore())
        defaultTokenServices.setSupportRefreshToken(true)
        defaultTokenServices.setTokenEnhancer(jwtAccessTokenConverter())
        return defaultTokenServices
    }
    
  • OAuth2RequestFactory:次のようにBeanとして実装されます

    @Bean
    fun oauthRequestFactory(clientsDetails: ClientDetailsService): OAuth2RequestFactory {
        return DefaultOAuth2RequestFactory(clientsDetails)
    }
    

このすべての依存関係がある場合、データベースに格納され、パスワードを指定せずに他のフローと同じフローに従うトークンを生成するために私がする必要があるのは、次のとおりです。

  1. Jwsトークンを解析し、その有効性を確認します
  2. グーグルで認証されたユーザーをロードする
  3. Authenticationクラスを使用してUsernamePasswordAuthenticationTokenを生成します。これは重要な部分です。DefaultTokenServices#createAccessTokenを呼び出して新しいトークンを取得します。リクエストを実行するには、いくつかの引数が必要です。
    • OAuth2RequestOAuth2RequestFactoryで作成できます
    • 以前に作成したAuthentication
    • このトークン要求をトリガーしているクライアントでTokenRequestを生成する必要があります。私の場合、それはハードコードされています

概要

したがって、トークンを手動で作成する方法を要約すると:

  • トークンサービスにトークンを提供するよう依頼する必要があります
  • そのためには、認証の詳細とリクエストを行うクライアントを提供する必要があります
  • これら2つを使用すると、新しいトークンを取得して、通常どおりに提供できます
1
droidpl

スプリングブート2.2.2プロジェクトでは、次のコードを使用してパスワードフローのサーバー側を実行しています。authorizedClientManager.setContextAttributesMapperはコンテキスト内の特定の属性を想定しているため、PasswordOAuth2AuthorizedClientProviderを指定する必要がありました。お役に立てば幸いです。

構成(application.yaml):

spring:
  security:
    oauth2:
      client:
        provider:
          yourOauthProvider:
            user-info-uri: ...
            authorization-uri: ...
            token-uri: ...

        registration:
          regId:
            clientId: ...
            clientSecret: ...
            provider: yourOauthProvider
            authorization-grant-type: password
            redirect-uri-template: "{baseUrl}/login/oauth2/code/{registrationId}"
            scope:

配線:

@Configuration
public class Oauth2ClientConfig {

    @Bean
    public OAuth2AuthorizedClientManager authorizedClientManager(
            ClientRegistrationRepository clientRegistrationRepository,
            OAuth2AuthorizedClientRepository authorizedClientRepository) {

        OAuth2AuthorizedClientProvider authorizedClientProvider =
                OAuth2AuthorizedClientProviderBuilder.builder()
                        .password()
                        .build();

        DefaultOAuth2AuthorizedClientManager authorizedClientManager =
                new DefaultOAuth2AuthorizedClientManager(
                        clientRegistrationRepository, authorizedClientRepository);
        authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
        authorizedClientManager.setContextAttributesMapper(r -> {
            Map<String, Object> m = new HashMap<>();
            m.put(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, r.getPrincipal().getPrincipal());
            m.put(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, r.getPrincipal().getCredentials());
            return m;
        });

        return authorizedClientManager;
    }
}

サービス:

class AuthService {
    @Autowired
    private OAuth2AuthorizedClientManager authorizedClientManager;
    public OAuth2AccessToken authenticate(String user, String password) {

        Authentication principal = new UsernamePasswordAuthenticationToken(
                user,
                password);

        OAuth2AuthorizeRequest authorizeRequest = 
            OAuth2AuthorizeRequest.withClientRegistrationId("regId")
                .principal(principal)
                .build();

        OAuth2AuthorizedClient authorizedClient =
            this.authorizedClientManager.authorize(authorizeRequest);

        return authorizedClient.getAccessToken();
    }
}
0
revau.lt