Spring OAuth2 - 在令牌存储中手动创建访问令牌

时间:2013-08-30 15:28:07

标签: java spring oauth spring-security oauth-2.0

我有一种情况,我想自己创建一个访问令牌(所以不通过通常的过程)。我想出了类似的东西:

@Inject
private DefaultTokenServices defaultTokenServices;

... 

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

唯一的问题是我不确定如何创建OAuth2Authentication(在我的代码中使用xxx的部分)。我有用户&客户信息,我知道我想授予此令牌的权限。

7 个答案:

答案 0 :(得分:17)

在这里,您的使用案例可能会根据您使用的流程略有不同。这适用于密码授权流程。有一些自定义类,如令牌存储,令牌增强等。但这只是为了我们自己的需要而修改的弹簧类的扩展版本。

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

答案 1 :(得分:12)

以下是使用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);
}

答案 2 :(得分:5)

其他方式,要手动生成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();
}

答案 3 :(得分:1)

这对我有用:

@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/

答案 4 :(得分:1)

我的解决方案基于Mop So的答案,但不是使用:

print(X_sparse.shape)
print(X.shape)

我用过:

return tokenEndpoint.getAccessToken(principal, parameters);

为什么呢?因为如果您使用tokenEndpoint.postAccessToken(principal, parameters); ,则endpoing将为您提供tokenEndpoint.getAccessToken(principal, parameters),因为它尚未使用HttpRequestMethodNotSupportedException方法调用。至少,这是我GET

发生的事情
spring-security-oauth2-2.0.13.RELEASE

答案 5 :(得分:0)

问题

我在这里列出的所有实现都遇到了问题,所以我终于设法使用无状态服务器,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和我的Google交换令牌进行编码和解码。
  • ClientDetailsService:声明为授权服务器一部分的bean。来自我的数据库

    覆盖有趣的configure(客户:ClientDetailsS​​erviceConfigurer){     client.jdbc(数据源) }

  • 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. 加载已通过google身份验证的用户
  3. 使用Authentication类生成UsernamePasswordAuthenticationToken。这是关键部分,调用DefaultTokenServices#createAccessToken以获取新令牌。它需要一些参数来执行请求:
    • OAuth2Request:可以使用OAuth2RequestFactory
    • 创建
    • 先前创建的Authentication
    • 我们需要与触发此令牌请求的客户端生成一个TokenRequest。就我而言,我已经硬编码了

摘要

因此,回顾一下如何手动创建令牌:

  • 我们需要要求令牌服务给我们一个令牌
  • 为此,我们需要提供身份验证详细信息和执行请求的客户端
  • 有了这2个,我们可以获得一个新令牌并正常投放

答案 6 :(得分:0)

在spring boot 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();
    }
}