首页 文章

Openid与数据库集成的Spring安全性

提问于
浏览
24

我是Spring和Spring Security的新手,希望有人能帮助我解决以下问题 .

我想要实现的是在OpenID提供程序(gmail)成功验证此用户之后提取用户的用户名和电子邮件地址,然后检查数据库以便为该用户加载用户模型 .

在我的spring-security.xml中,我有

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xmlns:security="http://www.springframework.org/schema/security"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context-3.0.xsd
                           http://www.springframework.org/schema/security 
                           http://www.springframework.org/schema/security/spring-security-3.0.xsd">

    <security:authentication-manager alias="openIDAuthenticationManager" />

    <bean id="authenticationSuccessHandler" class="org.school.openid.service.YouEatAuthenticationSuccessHandler">
        <property name="defaultTargetUrl" value="/krams/main/common" />
        <property name="attributes2UserDetails" ref="openIDAttributes2UserDetails" />
    </bean>

    <security:http >
        <security:anonymous enabled="false" />
        <security:logout />
        <security:openid-login user-service-ref="userDetailsServiceOpenIDImpl" authentication-success-handler-ref="authenticationSuccessHandler"
            login-page="/krams/auth/login" authentication-failure-url="/krams/auth/login?error=true">
            <security:attribute-exchange>
                <security:openid-attribute name="email" type="http://schema.openid.net/contact/email" required="true" />
                <security:openid-attribute name="firstName" type="http://axschema.org/namePerson/first" required="true" />
                <security:openid-attribute name="lastName" type="http://axschema.org/namePerson/last" required="true" />
            </security:attribute-exchange>
        </security:openid-login>
    </security:http>

    <bean id="openIDAttributes2UserDetails" class="org.school.openid.service.OpenIDAttributes2UserDetailsImpl" />

    <bean id="userDetailsServiceOpenIDImpl" class="org.school.openid.service.UserDetailsServiceOpenIDImpl" />

</beans>

我的问题出在UserDetailsServiceOpenIDImpl.java上

public class UserDetailsServiceOpenIDImpl implements UserDetailsService {

    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException, DataAccessException {
        System.out.println(username);
        //extract username and email address, HOW?
    }
}

print语句打印出类似的东西

https://www.google.com/accounts/o8/id?id=AItOawlq2C3EdFAuqp-ski_xkgB8jsEKbe-mZE

我的问题是

(1)如何从返回的URL中提取用户名和电子邮件地址(另外,我甚至不确定用户名和电子邮件地址是否正确返回)?

(2)通过在Eclipse上运行调试,当url(https://www.google.com/accounts/o8/id?id=AItOawlq2C3EdFAuqp-ski_xkgB8jsEKbe-mZE)返回时,似乎没有调用YouEatAuthenticationSuccessHandler .

谢谢 .

Edit: 感谢您的链接http://static.springsource.org/spring-security/site/docs/3.0.x/reference/ns-config.html#ns-openid .

它说“属性值作为身份验证过程的一部分返回,之后可以使用以下代码访问:...”

我已经添加了

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

进入loadUserByUsername方法 . 但“令牌”对象为空 .

Edit 2 通过以下页面https://fisheye.springsource.org/browse/spring-security/samples/openid/src/main/webapp/WEB-INF/applicationContext-security.xml?hb=true,我可以为用户提供额外的名称和电子邮件地址 . 我的spring-security.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xmlns:security="http://www.springframework.org/schema/security"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context-3.0.xsd
                           http://www.springframework.org/schema/security 
                           http://www.springframework.org/schema/security/spring-security-3.1.xsd">
    <security:authentication-manager alias="openIDAuthenticationManager" />
    <security:http pattern="/krams/auth/login" security="none"/>
    <security:http auto-config="true" access-denied-page="/krams/auth/denied">
        <security:intercept-url pattern="/krams/main/*" access="ROLE_USER" />
        <security:anonymous enabled="false" />
        <security:logout 
            invalidate-session="true"
            logout-success-url="/krams/auth/login"
            logout-url="/krams/auth/logout"/>
        <security:openid-login 
            user-service-ref="registeringUserService"
            login-page="/krams/auth/login" 
            authentication-failure-url="/krams/auth/login?error=true" 
            default-target-url="/krams/main/common">
            <security:attribute-exchange identifier-match="https://www.google.com/.*">
                <security:openid-attribute name="email" type="http://schema.openid.net/contact/email" required="true" />
                <security:openid-attribute name="firstName" type="http://axschema.org/namePerson/first" required="true" />
                <security:openid-attribute name="lastName" type="http://axschema.org/namePerson/last" required="true" />
            </security:attribute-exchange>
            <security:attribute-exchange identifier-match=".*yahoo.com.*">
                <security:openid-attribute name="email" type="http://axschema.org/contact/email" required="true"/>
                <security:openid-attribute name="fullname" type="http://axschema.org/namePerson" required="true" />
            </security:attribute-exchange>
        </security:openid-login>
        <!-- if remember is needed
         <security:remember-me token-repository-ref="tokenRepo"/>
         -->       
    </security:http>
    <bean id="tokenRepo" class="org.springframework.security.web.authentication.rememberme.InMemoryTokenRepositoryImpl" />
<!--
    A custom UserDetailsService which will allow any user to authenticate and "register" their IDs in an internal map
    for use if they return to the site. This is the most common usage pattern for sites which use OpenID.
 -->
   <bean id="registeringUserService" class="org.school.openid.service.CustomUserDetailsService" />
</beans>

我的CustomUserDetailsService.java

public class CustomUserDetailsService implements AuthenticationUserDetailsService {

    /*
    private final Map registeredUsers = new HashMap();
    */
       private static final List DEFAULT_AUTHORITIES = AuthorityUtils.createAuthorityList("ROLE_USER");
    protected static Logger logger = Logger.getLogger("service");    
    /**
     * Implementation of {@code AuthenticationUserDetailsService} which allows full access to the submitted
     * {@code Authentication} object. Used by the OpenIDAuthenticationProvider.
     */
    public UserDetails loadUserDetails(OpenIDAuthenticationToken token) {
        String id = token.getIdentityUrl();
        String email = null;
        String firstName = null;
        String lastName = null;
        String fullName = null;
        List attributes = token.getAttributes();
        for (OpenIDAttribute attribute : attributes) {
            if (attribute.getName().equals("email")) {
                email = attribute.getValues().get(0);
            }
            if (attribute.getName().equals("firstName")) {
                firstName = attribute.getValues().get(0);
            }
            if (attribute.getName().equals("lastName")) {
                lastName = attribute.getValues().get(0);
            }
            if (attribute.getName().equals("fullname")) {
                fullName = attribute.getValues().get(0);
            }
        }
        if (fullName == null) {
            StringBuilder fullNameBldr = new StringBuilder();
            if (firstName != null) {
                fullNameBldr.append(firstName);
            }
            if (lastName != null) {
                fullNameBldr.append(" ").append(lastName);
            }
            fullName = fullNameBldr.toString();
        }
        CustomUserDetails user = new CustomUserDetails(id,fullName,email, DEFAULT_AUTHORITIES);        
        logger.debug("Set username " + fullName + " email " + email);
        return user;
    }
}

我的CustomUserDetails.java

public class CustomUserDetails extends User {
    private static final long serialVersionUID = 1L;
    private String email;
    private String name;
    public CustomUserDetails(String id,String name, String email,Collection authorities) {
        super(name, "unused", true,true,true,true,authorities);
        this.email = email;
        this.name = name;
    }
    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

...
<repository>
    <id>org.springframework.maven.milestone</id>
    <name>Spring Maven Milestone Repository</name>
    <url>http://maven.springframework.org/milestone</url>
</repository>
...
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-core</artifactId>
    <version>3.1.0.RC1</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>3.1.0.RC1</version>
    <type>jar</type>
        <scope>compile</scope>
</dependency>
<dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-config</artifactId>
      <version>3.1.0.RC1</version>
    </dependency>
        <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-openid</artifactId>
        <version>3.1.0.RC1</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-openid</artifactId>
        <version>3.1.0.RC1</version>
        <type>pom</type>
        <scope>compile</scope>
    </dependency>

希望可以节省你一些时间 .

1 回答

  • 1

    我看到问题文本本身就包含了答案 . 我只是将它拉出来并将其作为答案发布给其他具有相同问题的开发人员 . 我花了一段时间才弄明白这个问题有答案!

    要访问用户电子邮件和名称,您需要在security xml文件中添加以下配置 .

    <security:attribute-exchange identifier-match="https://www.google.com/.*">
        <security:openid-attribute name="email" type="http://schema.openid.net/contact/email" required="true" />
        <security:openid-attribute name="firstName" type="http://axschema.org/namePerson/first" required="true" />
        <security:openid-attribute name="lastName" type="http://axschema.org/namePerson/last" required="true" />
    </security:attribute-exchange>
    <security:attribute-exchange identifier-match=".*yahoo.com.*">
        <security:openid-attribute name="email" type="http://axschema.org/contact/email" required="true"/>
        <security:openid-attribute name="fullname" type="http://axschema.org/namePerson" required="true" />
    </security:attribute-exchange>
    

    此后,它将在 AuthenticationUserDetailsService 类中访问,如下所示 .

    public UserDetails loadUserDetails(OpenIDAuthenticationToken token) {
        String id = token.getIdentityUrl();
            :
            :
        List attributes = token.getAttributes();
        for (OpenIDAttribute attribute : attributes) {
            if (attribute.getName().equals("email")) {
                email = attribute.getValues().get(0);
            }
            if (attribute.getName().equals("firstName")) {
                firstName = attribute.getValues().get(0);
            }
            if (attribute.getName().equals("lastName")) {
                lastName = attribute.getValues().get(0);
            }
            if (attribute.getName().equals("fullname")) {
                fullName = attribute.getValues().get(0);
            }
        }
            :
            :
        // form and return user object
    }
    

    考虑到我们现在使用更多基于Java的配置/ bean,将这些XML配置转换为基于Java的配置应该不是问题 .

    希望能帮助到你 .

相关问题