拥有 Spring 个 OAuth2 服务器以及第 3 方 OAuth 提供商

Own Spring OAuth2 server together with 3rdparty OAuth providers

在 Spring 引导应用程序中,我有一个 OAuth2 Authorization/Resource 服务器。基于此和 Spring 安全性,我保护了我的 Spring MVC REST API 端点。

除此之外,我想根据 Twitter、Facebook、Google.

等第三方 OAuth 提供商向我的 REST 端点添加身份验证

在我的应用程序中,我有两个实体 - UserSocialUserSocialUser 表示社交网络中的用户个人资料。 User 可以有 0-* 关联 SocialUsers。现在我可以在 Twitter 中对用户进行身份验证,之后我在我的数据库中创建两条记录 - User 和 SocialUser。 SocialUser 包含 access/refresh 由 Twitter 发布的令牌以及来自该社交网络的一些其他个人资料信息。

现在我不知道如何 link 这个从社交网络创建的用户与我现有的 authentication\authorization 流程。对于这个用户,我想创建我自己的(通过我自己的 OAuth2 授权服务器)accessToken 并将其提供给客户端。

此外,该用户在他的 User 实体中没有用户名、密码和电子邮件。 而且我也不知道如何手动创建自己的访问令牌并将其发送给客户端以供将来 API 调用。

我找到了一些例子:

@Inject
private TokenEndpoint tokenEndpoint;

public String createAccessToken(User user) {
    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", user.getPassword());
    parameters.put("scope", "read write");
    parameters.put("username", user.getUsername());

    // principal ??
    return tokenEndpoint.getAccessToken(principal, parameters);
}

但我不知道如何根据我的 User 实体创建 Principal,而且我不确定这是正确的方法。

所以,主要问题是 - 如何通过我自己的 OAuth 服务器为这个新用户手动生成这个新令牌?

请告诉我如何才能正确实施。谢谢。

更新:

我已将 ProviderSignInController 添加到我的应用程序中,现在能够与 Twitter 一起执行完整的 OAuth 舞蹈。此外,我还实现了自己的 Neo4jConnectionRepositoryNeo4jUsersConnectionRepository,因为我使用 Neo4j 作为主数据库。

@Bean
public ProviderSignInController providerSignInController() {
    return new ProviderSignInController(socialAuthenticationServiceLocator, usersConnectionRepository, new SignInAdapter() {

        @Override
        public String signIn(String userId, Connection<?> connection, NativeWebRequest request) {
            System.out.println("User ID: " + userId + " social display name: " + connection.getDisplayName());
            return null;
        }
    });
}

到目前为止,一切正常。

一个问题是 - 如何在 SignInAdapter.signIn 方法中通过我自己的 OAuth2 授权服务器 authenticate/authorize User

我想我需要为该用户创建 OAuth2Authentication 对象并将其放入安全上下文中。我说得对吗?如果是这样,你能给我举个例子吗?

所以你想要实现的是:当客户端将用户重定向到你的授权服务器(授权码或隐式授权)以获取令牌时,用户可以使用他最喜欢的社交网络登录。

如果我没理解错的话,您已经使用 Twitter (ProviderSignInController) 推出了自己的单点登录 (SSO) 实现,现在您想知道如何在 Twitter 响应时生成令牌 "OK".

我认为您把问题搞错了:与其构建您的 Twitter 客户端并以编程方式生成令牌,不如将社交 SSO 集成到 spring-security-oauth2 的流程中,它实际上是如何将社交 SSO 集成到 Spring 安全性中。

最后,它是关于您的授权服务器如何保护 AuthorizationEndpoint 的:/oauth/authorize。 由于您的授权服务器可以正常工作,因此您已经有一个扩展 WebSecurityConfigurerAdapter 的配置 class 来处理 /oauth/authorizeformLogin 的安全性。 这就是您需要整合社交内容的地方。

而不是使用 Spring 安全内置表单身份验证机制,您将必须插入您自己的安全性,允许用户使用表单登录,或启动与其他提供商的 SSO。
Spring 安全性由一堆抽象组成,但它实际上归结为为每个请求使用 Authentication 对象填充 SecurityContext

身份验证过程完成后,用户将继续/oauth/authorize,同意客户端访问某些范围,令牌将像往常一样交付,您无需以编程方式生成令牌。

我已经使用 SAML(Spring 安全 SAML 扩展)完成了这项工作,但在您的情况下,您应该深入研究 Spring Social projects,它似乎开箱即用地支持所有主要社交网络.
好消息是您已经有了一堆可用的工具,"bad news" 是您必须在一定程度上了解它们的工作原理才能将它们组合在一起。

这个 tutorial 展示了如何准确地实现这一目标(如果我理解正确的话):让 auth 服务器根据外部 oauth2 身份验证发布您自己的 oauth2 令牌。 对应代码可用here.

要点是除了 @EnableAuthorizationServer 之外还使用 @EnableOAuth2Client 并在 spring 安全默认过滤器之前插入 OAuth2ClientAuthenticationProcessingFilter 过滤器。