将 Spring Security 与 Facebook 登录集成

Posted

技术标签:

【中文标题】将 Spring Security 与 Facebook 登录集成【英文标题】:Integrate Spring Security with Facebook Login 【发布时间】:2014-06-19 20:18:47 【问题描述】:

我在我的项目中使用 Spring MVC 和 Spring Security。这使用我自己的用户数据进行身份验证。但现在我试图与 Facebook 整合。我在 Facebook 上创建了应用程序,这意味着我得到了客户 ID 和客户密码。我还阅读了 SO 中的一些问题和一些文档,但仍然卡住了......

我创建控制器以使用 Facebook 登录:

import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/login/")
public class LoginController 

    String fb_app_id="my_client_id";
    String redirect_url="localhost:8888";
    String state="public_profile,email,user_friends";
    String key="my_client_secret";

    @RequestMapping("/facebook")
    public String login( ModelMap model) 

        String url="https://www.facebook.com/dialog/oauth/?"
                   + "client_id=" + fb_app_id
                   + "&redirect_uri=" + redirect_url
                   + "&scope=email,publish_stream,user_about_me,friends_about_me"
                   + "&state=" + key
                   + "&display=page"
                   + "&response_type=code";
        return "redirect:"+url;

    


我认为它有效,因为当我尝试连接时,我可以在下面使用 javascript 显示我的名字:

function testAPI() 
  console.log('Welcome!  Fetching your information.... ');
  FB.api('/me', function(response) 
    console.log('Good to see you, ' + response.name + '.');
    document.getElementById('status').innerhtml = 'Good to see you, ' +
      response.name;
  );

但我仍然对如何将它与 Spring Security 集成感到困惑。如果有人有任何例子,我将不胜感激......

这是我的 spring-security.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/security
           http://www.springframework.org/schema/security/spring-security-3.1.xsd">

    <http pattern="/common/*" security="none" />

    <http auto-config="true">
        <intercept-url pattern="/maintenance/*" access="ROLE_USER" />
        <intercept-url pattern="/_ah/*" access="ROLE_USER" />
        <intercept-url pattern="/predict/*" access="ROLE_USER" />

        <form-login login-page='/' default-target-url='/predict/list'
            login-processing-url="/login_check" authentication-failure-url="/index?login_error=2"
            always-use-default-target="true" />
        <logout logout-url="/logout" logout-success-url="/index" />
    <!--    <custom-filter ref="socialAuthenticationFilter" before="PRE_AUTH_FILTER" /> -->
    <!--    <custom-filter before="FORM_LOGIN_FILTER"
            ref="facebookAuthenticationFilter" /> -->
    </http>

    <authentication-manager>
        <authentication-provider ref="gaeAuthenticationProvider" />
    <!--    <authentication-provider ref="authenticationProviderFacebook"> 
        </authentication-provider>-->
    </authentication-manager>

    <beans:bean id="gaeAuthenticationProvider"
        class="com.games.predictor.security.AuthenticationProvider" />

</beans:beans>  

我有自己的类来使用 JPA 对用户数据进行身份验证...

package com.games.predictor.security;

import java.util.List;

import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

import com.games.predictor.UserDAO;


public class AuthenticationProvider extends AbstractUserDetailsAuthenticationProvider

    //private SecurityDao securityDao; 

    @Override
    protected UserDetails retrieveUser(String username,
            UsernamePasswordAuthenticationToken authentication)
            throws AuthenticationException
    
        final String password = authentication.getCredentials().toString();
        System.out.println(username+"===="+password);
        //This line for validating user with database
        boolean isValidUser = UserDAO.INSTANCE.isValidUser(username, password);
        if (isValidUser)
        
            final List<SimpleGrantedAuthority> authorities = UserDAO.INSTANCE.getAuthoritiesByUser(username);
            //User u=new User(username,password,);
            return new User(username, password, true, true, true, true, authorities);
        
        else
        
            authentication.setAuthenticated(false);
            throw new BadCredentialsException("Username/Password does not match for " 
                + authentication.getPrincipal());
        

    

    @Override
    protected void additionalAuthenticationChecks(UserDetails arg0,
            UsernamePasswordAuthenticationToken arg1)
            throws AuthenticationException 
        // TODO Auto-generated method stub

    

我在过去几天做了一些研究,但仍然卡住了。

我的项目堆栈:Java、Spring MVC、Spring Security、Google App Engine、Google Data Store、JPA。 (添加了 Spring Social Core 和 Spring Social Facebook)

【问题讨论】:

你真的不应该自己做任何这些......你检查过吗:projects.spring.io/spring-security-oauth/docs/oauth2.html,这是项目链接:projects.spring.io/spring-security-oauth 如果你想要一个示例实现,请检查这个。github.com/timenkov/facebook_login 【参考方案1】:

我认为您不应该手动处理 Facebook。您可以使用一个非常简单的库:https://github.com/pac4j/spring-security-pac4j 来验证 OAuth(Facebook、Twitter、Google...)、CAS、SAML、OpenID (Connect) 和 GAE。查看演示:https://github.com/pac4j/spring-security-pac4j-demo

【讨论】:

【参考方案2】:

Daniel 能否请您详细说明您在哪里卡住了。我使用相同的堆栈来集成 facebook 登录。但我没有使用 Spring Social。我相信这不是必需的。

将 facebook 登录与现有登录集成的步骤。

    在您的 jsp 中使用 facebook javascript plugin 进行 Facebook 登录。 一旦用户批准您的应用程序。 OAuth 生成一个身份验证令牌,使用该令牌通过图形 API 获取客户端的电子邮件 ID。 使用 Ajax 将电子邮件 ID 发送到服务器。 将发送到服务器端的电子邮件 ID 与数据库中的电子邮件 ID 进行比较。 如果电子邮件 ID 相同,请登录用户。

身份验证令牌是临时的,因此我发现将其发送到服务器端或保存在数据库中是没有意义的。它保存在客户端本地。并且 fb javascript 插件会处理它。这样就省去了实施 spring social facebook 的麻烦。

我看到您正在使用控制器进行 facebook 登录,这不是必需的,相信我使用 fb javascript 插件真的很简单。

【讨论】:

嗨,感谢您的回答。我的问题是将 Facebook 登录与 Spring Security Session 集成时。我看到有些人将它与 spring social 和 spring security 一起使用。但是我在尝试实现其中一个示例时遇到了问题。 Underdog 错过了这一点-您不应该获取在客户端生成的客户端的电子邮件 ID,因为它可以很容易地被其他一些电子邮件修改,因此不应该进入的人可以进入.返回 auth 用户令牌后,您应该将该令牌发送到服务器端,您需要在服务器端检查此令牌是否仍然是生成的令牌,正如 facebook 在此处 developers.facebook.com/docs/facebook-login/login-flow-for-web/… 所推荐的那样。一旦您确认这一点,您就可以将该 facebook 用户作为您存在的用户之一登录。

以上是关于将 Spring Security 与 Facebook 登录集成的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security + Keycloak 授权:如何将端点与资源相关联?

将 spring-security 与 spring-webflux 一起使用时禁用 WebSession 创建

是否可以将 Spring Security 的 AOP 与 Java Security Manager 合并?

将 Spring Security 与 EJB 或 Spring 一起使用?

我可以将 Spring Social 与 Spring Security 一起使用吗?

将 Spring MVC Spring Security 与 Undertow Web 容器集成