如何将 OAuth 身份验证与 Spring Security 联系起来

Posted

技术标签:

【中文标题】如何将 OAuth 身份验证与 Spring Security 联系起来【英文标题】:How to tie OAuth authentication with Spring Security 【发布时间】:2017-08-02 18:46:22 【问题描述】:

我有一个 Grails 2.5.3 应用程序,目前使用 spring 安全插件进行身份验证。用户使用用户名/密码登录。

我现在更新了应用程序以支持 OAuth 身份验证(使用 ScribeJava)。用户可以单击将他们重定向到 OAuth 提供者页面的链接,并在成功输入凭据后将他们重定向回我的应用程序。但是,我无法将此功能与 spring 安全插件绑定,因此当用户被重定向回我的应用程序时(从 OAuth 成功登录后),我实际上可以看到他们已登录并继续使用我所有的 spring像<sec:ifLoggedIn> 这样的安全好东西。

有谁知道这样做的方法或有一个我可以看看的例子吗?

这是我使用 OAuth 对用户进行身份验证的方式:

//called when user clicks "login using oauth"
def authenticate() 
    OAuthService service = new ServiceBuilder()
                              .apiKey(grailsApplication.config.my.sso.clientid)
                              .apiSecret(grailsApplication.config.my.sso.clientsecret)
                              .build(MyApi.instance());
    String url =  service.getAuthorizationUrl();
    return redirect(url: url)


//called when oauth provider redirects to my application
def authorization_code() 
    def code = params.code
    OAuthService service = new ServiceBuilder()
                              .apiKey(grailsApplication.config.my.sso.clientid)
                              .apiSecret(grailsApplication.config.my.sso.clientsecret)
                              .build(MyApi.instance());
    println code                          
    OAuth2AccessToken accessToken = service.getAccessToken(code);
    String userProfileUrl = grailsApplication.config.my.sso.authdomain+"/userinfo"
    final OAuthRequest request = new OAuthRequest(Verb.GET, userProfileUrl);
    service.signRequest(accessToken, request);
    final Response response = service.execute(request);
    println(response.getCode());
    println(response.getBody());        
    render (text: code)

【问题讨论】:

以下答案对您有帮助吗? 【参考方案1】:

每当您通过OAuth 进行身份验证时,远程服务器每次都会返回一个unique id (some numeric value)。 您可以使用该id 来验证您的最终用户,并使用springsecurity.reauthenticate() 方法对用户进行身份验证。

步骤:

    当用户与服务提供商连接(首次验证)时。 服务提供商向您发送unique id。将 unique id 保存在 用户表。 当用户通过该服务提供商登录时。再次服务提供商 发送unique id。检查您的系统中是否存在unique id, 如果用户存在该唯一ID,则使用 springsecurity.reauthenticate(userInstance) 方法来验证用户。现在您可以使用弹簧安全功能。

查看链接:http://www.jellyfishtechnologies.com/grails-2-2-0-integration-with-facebook-using-grails-oauth-plugin/

【讨论】:

【参考方案2】:

假设您从 Oauth 提供商那里获得了用户详细信息,您只需要 设置特定用户的安全上下文

通过解析JSON之类的方式获取用户详细信息

def oauthResponse = JSON.parse(response?.getBody())
Map data = [
                    id          : oauthResponse.id,
                    email       : oauthResponse.email,
                    name        : oauthResponse.name,
                    first_name  : oauthResponse.given_name,
                    last_name   : oauthResponse.family_name,
                    gender      : oauthResponse.gender,
                    link        : oauthResponse.link
            ]

在我们的例子中,我们使用电子邮件 ID 作为用户名。

因此,当我们获取用户数据时,只需检查用户是否已在系统中注册或如下所示

//load the user details service bean
def userDetailsService

//check if user is already registered on our system
User user = User.findByEmail(data?.email)
if (user) 

    //If user exists load his context
    userDetails = userDetailsService.loadUserByUsername(data?.email)
 else 

    //create the new user
    //Assign the role to it

    //load his context as below
   userDetails = userDetailsService.loadUserByUsername(data?.email)

用户注册成功后,我们只需要像下面这样加载他的上下文

def password

//setting spring security context
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(userDetails, password == null ? userDetails.getPassword() : password, userDetails.getAuthorities()))

一旦加载了 spring 安全上下文,您就可以将用户重定向到您的登录页面。

现在 oauth 用户将像任何其他具有相同角色的用户一样访问资源。

【讨论】:

以上是关于如何将 OAuth 身份验证与 Spring Security 联系起来的主要内容,如果未能解决你的问题,请参考以下文章

使用 Spring Boot OAuth2 针对 Google 进行身份验证时如何将 google 用户电子邮件发送到白名单用户

在 Spring Boot 2 上实现基于过滤器的 JWT 身份验证与 OAuth2 JWT 身份验证

如何在 spring-security-oauth 中获取经过身份验证的用户

如何在 Spring Boot oauth2 资源服务器中使用自定义身份验证标头

如何在 Spring Boot 中实现 oAuth2 和 JWT 身份验证? [关闭]

使用Spring启动进行Oauth2身份验证