Spring Security с Openid и интеграцией с базой данных - PullRequest
25 голосов
/ 05 сентября 2011

Я очень плохо знаком с 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 is

public class UserDetailsServiceOpenIDImpl implements UserDetailsService {

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

Оператор print печатает что-то вроде

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

Мои вопросы

(1) Как я могу извлечь имя пользователя и адрес электронной почты из возвращенного URL-адреса (кроме того, я даже не уверен, правильно ли вернулись имя пользователя и адрес электронной почты)?

(2) При запуске отладки в Eclipse YouEatAuthenticationSuccessHandler, по-видимому, не вызывается, когда возвращается URL (https://www.google.com/accounts/o8/id?id=AItOawlq2C3EdFAuqp-ski_xkgB8jsEKbe-mZE).

Спасибо.

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. Но объект "токен" является нулевым.

Редактировать 2 На следующей странице https://fisheye.springsource.org/browse/spring-security/samples/openid/src/main/webapp/WEB-INF/applicationContext-security.xml?hb=true, я могу добавить имя и адрес электронной почты для пользователя. Моя весна-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;
    }
}

И

...
<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 голос
/ 09 января 2017

Как я вижу, сам текст вопроса содержит ответ.Я просто вытаскиваю это и публикую как ответ для ясности другим разработчикам с той же проблемой. Мне потребовалось некоторое время, чтобы выяснить, что на вопрос есть ответ!

Чтобы получить доступ к электронной почте и имени пользователя, вам необходимо добавить приведенную ниже конфигурацию в файл 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, переводя эти XML-конфигурации в Javaконфигурация не должна быть проблемой.

Надеюсь, это поможет.

...