1

Spring Security を使用するアプリケーションで facebook ログイン + DB 認証を使用したいと考えています。

そのため、次のようなリクエストを送信する index.jsp ページに fb ボタンを 1 つ追加しました。

function testAPI() {
    console.log('Welcome!  Fetching your information.... ');
    FB.api('/me', function(response) {
        console.log('Good to see you, ' + response.name + '.' + response.email);
        window.location = "<%=request.getContextPath()%>/j_spring_facebook_security_check";
    });
}

applicationContext-Security.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans">
    //spring security 3.
    <security:http auto-config="true" use-expressions="true" access-denied-page="/accessDenied.jsp">
        <security:form-login login-page="/index.jsp"
            default-target-url="/jsp/home.jsp"
            authentication-failure-handler-ref="authenticationFailureHandler"/>

        <security:intercept-url pattern="/jsp/listInBetweenPlaces.jsp"
            access="permitAll" />

        <security:intercept-url pattern="/jsp/home.jsp"
            access="permitAll" />

        <security:intercept-url pattern="/index.jsp"
            access="permitAll" />

        <security:intercept-url pattern="/jsp/*"
            access="isAuthenticated()" />

        <security:logout logout-url="/j_spring_security_logout" logout-success-url="/index.jsp?logout=success" 
            invalidate-session="true"  />

        <security:custom-filter before="FORM_LOGIN_FILTER"
            ref="facebookAuthenticationFilter" />
</security:http>

    <bean id="facebookAuthenticationFilter" class="org.springframework.security.facebook.FacebookAuthenticationFilter">
        <property name="authenticationManager" ref="authenticationManager"/>

        <property  name = "authenticationSuccessHandler">
            <bean  class = "org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler">
                <property  name = "defaultTargetUrl"  value = "/jsp/home.jsp"  />
                <property  name = "alwaysUseDefaultTargetUrl"  value = "true"  />
            </bean>
        </property>

        <property  name = "authenticationFailureHandler">
            <bean  class = "org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
                <property  name = "defaultFailureUrl"  value = "/fb/failure.jsp"  />
            </bean>
        </property>
    </bean>

    <bean id="authenticationProviderFacebook" class="org.springframework.security.facebook.FacebookAuthenticationProvider">
        <property name="roles" value="ROLE_FACEBOOK_USER" />
    </bean>

    <bean id="facebookHelper"  class="org.springframework.security.facebook.FacebookHelper">
        <property  name="apiKey"  value="my_api_key"  />
        <property  name="secret"  value="my_secret_key"  />
    </bean>

    <bean id="customUserDetailsService" class="com.onmobile.carpool.authentication.CustomUserDetailsService">
        <!--  <property name="carpoolService" ref="carpoolServiceImpl" /> -->
    </bean>

    <security:authentication-manager alias="authenticationManager">
        <security:authentication-provider user-service-ref="customUserDetailsService">
            <security:password-encoder hash="md5" />
        </security:authentication-provider>
        <security:authentication-provider ref="authenticationProviderFacebook">
        </security:authentication-provider>
    </security:authentication-manager>
</beans>

FacebookAuthenticationFilter.java:

public class FacebookAuthenticationFilter extends
                AbstractAuthenticationProcessingFilter implements
                ApplicationContextAware {

    public static final String DEFAULT_FILTER_PROCESS_URL = "/j_spring_facebook_security_check";
    private FacebookHelper facebookHelper = null ;
    private ApplicationContext ctx;
    protected FacebookAuthenticationFilter() {
        super(DEFAULT_FILTER_PROCESS_URL);
    }

    public Authentication attemptAuthentication(HttpServletRequest req,
                        HttpServletResponse res) throws AuthenticationException,
                        IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        if(facebookHelper == null){
            facebookHelper = (FacebookHelper) ctx
                    .getBean("facebookHelper");
        }

        Long uid = null;
        String sessionkey = null ;
        try {
            uid = facebookHelper.getLoggedInUserId(request, response);
            sessionkey = facebookHelper.lookupSessionKey(request);
        } catch (FacebookUserNotConnected e) {
            throw new AuthenticationCredentialsNotFoundException(
                                        "Facebook user not connected", e);
        }

        FacebookAuthenticationToken token = new FacebookAuthenticationToken(uid);
        token.setSessionkey(sessionkey);
        token.setDetails(authenticationDetailsSource.buildDetails(request));

        AuthenticationManager authenticationManager = getAuthenticationManager();
        Authentication authentication = authenticationManager
                                .authenticate(token);

        return authentication;
    }

    public void setApplicationContext(ApplicationContext ctx)
                        throws BeansException {
        this.ctx = ctx;
    }

    public FacebookHelper getFacebookHelper() {
        return facebookHelper;
    }

    public void setFacebookHelper(FacebookHelper facebookHelper) {
        this.facebookHelper = facebookHelper;
    }

}

私はいつもこの呼び出しに問題があります:

 uid = facebookHelper.getLoggedInUserId(request, response);

getLoggedInUserIdFacebookHelper.javaの詳細:

public Long getLoggedInUserId(HttpServletRequest request,
                    HttpServletResponse response) throws FacebookUserNotConnected {

    FacebookWebappHelper<Document> facebook = new FacebookWebappHelper<Document>(
                        request, response, apiKey, secret);
    Long uid = facebook.getUser();

    if (uid == null)
            throw new FacebookUserNotConnected(
                            "Facebook user id could not be obtained");
    return uid;
}

以下の行は常に null と評価されるため、例外がスローされます。

Long uid = facebook.getUser();

以下のリンクからFacebook関連のクラスを受講しました。

https://code.google.com/p/spring-security-facebook/source/browse/trunk/src/?r=4#src%2Fmain%2Fjava%2Forg%2Fspringframework%2Fsecurity%2Ffacebook

私の必要性は、ユーザーがDBチェックまたはFB認証を介してアプリにログインできるようにすることです。

私はこれを進めることができません.誰かが私が欠けているものを指摘してもらえますか. 私は常にfailure.jspにリダイレクトされています。FB アカウントで有効にする必要があるものはありますか? または、UI からフィルターに間違ったデータを渡していますか?

これに関する完全なチュートリアルをどこにも見つけることができません。誰かが正しいリンクを指摘できますか。

4

1 に答える 1

0

私が取り組んでいる最近のアプリで同様のことをしました。Spring-Oauth プロジェクトを使用して oauth 認証を実行することを検討しましたが、後で spring-oauth ではアプリケーションで既に認証されている必要があり、オンラインで見つけた他のすべてのソリューションは時代遅れであることに気付きました。

数日間苦労した後、これが私がやったことです。アプリで PrimeFaces と一緒に JSF を使用していますが、アイデアが得られることを願っています。このアプローチは、最初に Facebook Javascript API を使用して Facebook 認証を実行することです。これを行う方法については、Facebook ページにたくさんの例があります。

login.xhtml - Facebook API セクション

...
FB.Event.subscribe('auth.authResponseChange', function(response) {
  // Here we specify what we do with the response anytime this event occurs. 
  if (response.status === 'connected') {
    //a user has logged in to the app
    var responseToken = response.authResponse.accessToken;
    var responseUserId = response.authResponse.accessToken;
    loginJS([{name:'token', value: responseToken}, {name:'name', value: responseUserId}]);                      
  } 
});
...

ページの本文のどこかに、これも追加します。

<p:remoteCommand name="loginJS" action="#{userBean.facebookLogin}" immediate="true"  process="@this" />;

p:remoteCommandはマネージド Bean (userBean) の facebookLogin 関数を呼び出します。この関数は、リクエストから 2 つのパラメーター (userId、token) を取得します。あなたの場合、必要なことは、javascript から「ログイン」サーブレットを呼び出し、2 つのパラメーターを要求の一部として渡すことだけです。

UserBean.java

public String facebookLogin(){
    FacesContext context = FacesContext.getCurrentInstance();
    Map<String, String> map = context.getExternalContext().getRequestParameterMap();
    String userToken = map.get("token");
    String name = map.get("name");

    if(logger.isLoggable(Level.FINEST)){
        logger.finest("Login attempt via facebook. Token: "+ userToken);
    }

    Authentication auth = new FacebookTokenAuthentication(userToken, name);

    SecurityContextHolder.getContext().setAuthentication(auth);

    return "home?faces-redirect=true";
}

FacebookTokenAuthentication.java

public class FacebookTokenAuthentication implements Authentication {

    /**
     * 
     */
    private static final long serialVersionUID = 4218179259794454698L;
    private String token;
    private String name;

    public FacebookTokenAuthentication(String token, String name) {
        this.token = token;
        this.name = name;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return new ArrayList<GrantedAuthority>(0);
    }

    @Override
    public Object getCredentials() {
        return token;
    }

    @Override
    public Object getDetails() {
        return null;
    }

    @Override
    public Object getPrincipal() {
        return null;
    }

    @Override
    public boolean isAuthenticated() {
        return false;
    }

    @Override
    public void setAuthenticated(boolean isAuthenticated)
            throws IllegalArgumentException {
    }

    @Override
    public String getName() {
        return name;
    }
}

FacebookAuthenticationProvider.java

最後の部分は、facebook 認証プロバイダーを作成することです。この認証プロバイダーは、facebook API を呼び出してユーザー情報を取得し、データベース内で一致するユーザーを検索します。データベース内のユーザーの facebook ID をマップするか、電子メール アドレスを使用してユーザーを見つけることができます。この部分では、spring-social FacebookTemplate を使用して Facebook のプロフィール情報を取得しました。

public class FacebookAuthenticationProvider implements AuthenticationProvider {
    private static final Logger logger = Logger
            .getLogger(FacebookAuthenticationProvider.class.getName());

    /*
     * (non-Javadoc)
     * 
     * @see org.springframework.security.authentication.AuthenticationProvider#
     * authenticate(org.springframework.security.core.Authentication)
     */
    @Override
    public Authentication authenticate(Authentication auth)
            throws AuthenticationException {
        Authentication resultAuth = null;
        if (logger.isLoggable(Level.FINEST)) {
            logger.finest("Attempting to authenticate user via the FacebookAuthenticationProvider.");
        }

        if (auth.isAuthenticated()) {
            return auth;
        }

        if (auth instanceof FacebookTokenAuthentication) {

            FacebookTokenAuthentication fbAuth = (FacebookTokenAuthentication) auth;
            String token = (fbAuth.getCredentials() != null) ? fbAuth
                    .getCredentials().toString() : null;

            if (logger.isLoggable(Level.FINEST)) {
                logger.finest("Creating facebook template. Token:" + token);
            }

            FacebookTemplate fbTemplate = new FacebookTemplate(token);

            FacebookProfile userProfile = fbTemplate.userOperations()
                    .getUserProfile();

            // LOOKUP THE USER IN YOUR DATABASE
            User user = //ADD CUSTOM USER LOOKUP HERE;

            resultAuth = new PreAuthenticatedAuthenticationToken(user, token);
            resultAuth.setAuthenticated(true);
        } else {

            throw new BadCredentialsException("Invalid credentials.");
        }

        return resultAuth;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.springframework.security.authentication.AuthenticationProvider#supports
     * (java.lang.Class)
     */
    @Override
    public boolean supports(Class<?> auth) {
        return auth.equals(FacebookTokenAuthentication.class);
    }

} 

AuthenticationProvider を Spring 構成に追加することを忘れないでください

于 2014-02-01T20:12:28.313 に答える