18

我有一种情况,我想自己创建一个访问令牌(所以不是通过通常的过程)。我想出了这样的事情:

@Inject
private DefaultTokenServices defaultTokenServices;

... 

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

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

4

7 回答 7

19

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

        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);
于 2013-09-27T18:15:38.487 回答
15

以下是使用 TokenEndpoint 接口(用于公开 REST 服务)生成 Token 的方法:

@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);
}
于 2015-03-23T11:02:45.853 回答
10

其他方式,手动生成一个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();
}
于 2016-11-25T06:56:13.740 回答
3

我的解决方案基于 Mop So 的回答,但没有使用:

return tokenEndpoint.getAccessToken(principal, parameters);

我用了:

tokenEndpoint.postAccessToken(principal, parameters);

为什么?因为如果你使用tokenEndpoint.getAccessToken(principal, parameters)endpoing 会抛出你 aHttpRequestMethodNotSupportedException因为它没有被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();
}
于 2018-05-25T23:17:11.097 回答
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/

于 2018-03-14T10:11:29.090 回答
1

问题

我对这里列出的所有实现都有问题,所以我终于设法使用无状态服务器、oauth2 和 google social 获得了自己的实现。它只是这里缺少的教程的最后一部分

对我来说,问题是在执行 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 和我的交换令牌进行编码和解码。
  • ClientDetailsService: bean 声明为授权服务器的一部分。来自我的数据库

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

概括

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

  • 我们需要请求代币服务给我们一个代币
  • 为此,我们需要提供身份验证详细信息和执行请求的客户端
  • 有了这两个,我们可以获得一个新的令牌并正常服务它
于 2018-12-27T13:41:09.167 回答
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();
    }
}
于 2020-01-09T09:51:24.543 回答