使用 Spring Security 3.0.2 进行 OpenId 身份验证和自动注册

Posted

技术标签:

【中文标题】使用 Spring Security 3.0.2 进行 OpenId 身份验证和自动注册【英文标题】:OpenId authentication and automatic registration with Spring Security 3.0.2 【发布时间】:2011-02-13 00:37:15 【问题描述】:

我正在使用带有 OpenId 登录和注册的 spring security 3.0.2 实现一个应用程序。 我可以成功登录,但如果用户未注册,我想做:

1) 获取一些 OpenId 属性,例如电子邮件和姓名。 2) 向用户显示一个注册表单,其中仅包含这两个字段并填写了 OpenId URI。

我一直在寻找很多,但我没有找到一种“优雅”的方式来做到这一点。 我想知道你们中的一些人是否可以提出一个解决方案来在我的应用中实施这个策略。

提前致谢。

【问题讨论】:

【参考方案1】:

在用户自己注册/登录之前,您不能显示电子邮件和姓名,因为他必须先允许应用访问他的个人资料。您可以在他登录后向他显示此页面以及他的 openid、邮件等。

定义要使用的属性:

<openid-login login-page="/openidlogin.jsp" authentication-failure-url="/openidlogin.jsp?login_error=true">
  <attribute-exchange>
    <openid-attribute name="email" type="http://schema.openid.net/contact/email" required="true" count="2"/>
    <openid-attribute name="name" type="http://schema.openid.net/namePerson/friendly" />
  </attribute-exchange>
</openid-login>

然后在用户登录后访问属性:

OpenIDAuthenticationToken token = (OpenIDAuthenticationToken)SecurityContextHolder.getContext().getAuthentication();
List<OpenIDAttribute> attributes = token.getAttributes();

看看example from the spring repository和OpenId Support Documentation。

【讨论】:

@dude :我有类似的问题,并使用了你建议的答案......但代码似乎不起作用......看看***.com/questions/7228733/…【参考方案2】:

Spring security

但是,您可以使用 aspectJ 的解决方法。定义以下方面:

package org.acoveo.spring.utils;
@Aspect
public class OpenIDSpringAuthenticationHackAspect 
    static ThreadLocal<Authentication> authHolder = new ThreadLocal<Authentication>();
    @Around(value="execution(* org.springframework.security.openid.OpenIDAuthenticationProvider.authenticate(..))")
    public Object around(ProceedingJoinPoint jp) throws Throwable 
        try 
            Authentication auth = (Authentication) jp.getArgs()[0];
            authHolder.set(auth);
            Object returnVal = jp.proceed();
            authHolder.set(null);
            return returnVal;
        catch(Throwable e) 
            System.out.println("Exception while running OpenIDSpringAuthenticationHackAspect");
            e.printStackTrace();
            return null;
        
    
    public static Authentication getTransientAuthentication() 
        return authHolder.get();
    

并在你的 aop.xml 中注册它:

<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">  
<aspectj>
    <weaver options="-showWeaveInfo -verbose" />
    <weaver>
        <include within="org.springframework.security.openid..*" />
        <!-- This is required to make the spring instrument javaagent work with hibernate CGLIB
         -->
        <exclude within="*..*CGLIB*" />
    </weaver>
    <aspects>
        <aspect name="org.acoveo.spring.utils.OpenIDSpringAuthenticationHackAspect" />
    </aspects>
</aspectj>

然后在您的 UserDetailsS​​ervice 中,您可以访问 OpenID 属性,如下所示:

public UserDetails loadUserByUsername(String username, boolean includeTemporary) throws UsernameNotFoundException, DataAccessException 
    Authentication auth = OpenIDSpringAuthenticationHackAspect.getTransientAuthentication();
    if(auth != null && auth instanceof OpenIDAuthenticationToken) 
        // First try to find the user by their openid email address
        OpenIDAuthenticationToken openIdToken = (OpenIDAuthenticationToken)auth;
        String email = null;
        for(OpenIDAttribute attr : openIdToken.getAttributes()) 
            if("email".equals(attr.getName()) && attr.getValues() != null && !attr.getValues().isEmpty()) 
                email = attr.getValues().get(0);
                break;
            
        
        // TODO retrieve and return user

【讨论】:

请记住,您仍然需要使用 标签告诉 spring 您需要 email 属性。

以上是关于使用 Spring Security 3.0.2 进行 OpenId 身份验证和自动注册的主要内容,如果未能解决你的问题,请参考以下文章

在 Grails 中使用 Pre/Post Spring-Security Annotations

Spring Framework,Spring Security - 可以在没有 Spring Framework 的情况下使用 Spring Security?

仅使用 Spring-Security(或)Spring 进行授权

在使用 Oauth、SAML 和 spring-security 的多租户的情况下从 spring-security.xml 中获取错误

Spring security:Spring security 如何在 SessionRegistry 中注册新会话?

未调用 Spring Security j_spring_security_check