Spring Security 与 Openid 和数据库集成

发布于 2024-12-03 12:37:28 字数 12127 浏览 1 评论 0原文

我对 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>

的问题是 UserDetailsS​​erviceOpenIDImpl.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)已返回。

谢谢。

编辑: 感谢您的链接 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 方法中。但“token”对象为空。

编辑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>

我的 CustomUserDetailsS​​ervice.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>

可以节省您一些时间。

I am very new to Spring and Spring Security, and hoping someone can help me to solve the following problem.

What I want to achieve is to extract user's username and email address after this user is successfully authenticated by OpenID provider(gmail), then check with the database in order to load the usermodel for this user.

In my spring-security.xml, i have

<?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>

my problem is at UserDetailsServiceOpenIDImpl.java is

public class UserDetailsServiceOpenIDImpl implements UserDetailsService {

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

The print statement prints out something like

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

My questions are

(1) How could I extract the username and the email address from the returned url (also, I am not even sure if the username and email address returned correctly)?

(2) By running the debug on Eclipse, the YouEatAuthenticationSuccessHandler seems not called when the url (https://www.google.com/accounts/o8/id?id=AItOawlq2C3EdFAuqp-ski_xkgB8jsEKbe-mZE) returned.

Thanks.

Edit:
thanks for the link http://static.springsource.org/spring-security/site/docs/3.0.x/reference/ns-config.html#ns-openid.

It says that "The attribute values are returned as part of the authentication process and can be accessed afterwards using the following code:..."

I have added

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

into loadUserByUsername method. But the "token" object is null.

Edit 2
By following page https://fisheye.springsource.org/browse/spring-security/samples/openid/src/main/webapp/WEB-INF/applicationContext-security.xml?hb=true, i am able to extra the name and email address for the user.
My 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>

My 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;
    }
}

My 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;
    }
}

And

...
<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>

Hope can save you some time.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

冰火雁神 2024-12-10 12:37:28

正如我所见,问题文本本身包含答案。我只是将其拉出来并将其作为答案发布,以便让其他具有相同问题的开发人员清楚地了解。 这个问题的答案!

我花了一段时间才找到 name,您需要在 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>

此后,可以在 AuthenticationUserDetailsS​​ervice 类中访问它,如下所示。

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 的配置应该不成问题。

希望有帮助。

As I see that question text itself contains the answer. I am just pulling it out and posting it as the answer for the sake of clarity to other developers with the same problem. It took me a while to figure out that question has the answer!

To access user email & name, you need to add below configuration in the security xml file.

<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>

Thereafter, it will be accessible in the AuthenticationUserDetailsService class, as shown below.

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
}

Considering that we use more of Java-based configuration/beans now, translating these XML configuration to Java-based configuration shouldn't be a problem.

Hope it helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文