使用spring security oauth集成单点登录

时间:2016-08-24 07:09:25

标签: spring spring-security single-sign-on spring-security-oauth2

我正在开发一个使用Spring Security OAuth2保护少量REST API的应用程序。身份验证工作正常。现在我想为每个帐户实现单点登录功能。一旦用户成功使用他的凭据从一个设备登录然后它不可能从其他设备登录相同的使用用户。那时用户只允许一次登录。如果他想登录其他设备,他应该从已经登录的设备注销。如何在春天安全oauth.Below是我的代码。

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:oauth="http://www.springframework.org/schema/security/oauth2"
          xmlns:context="http://www.springframework.org/schema/context"
          xmlns:sec="http://www.springframework.org/schema/security" xmlns:mvc="http://www.springframework.org/schema/mvc"
          xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
                http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
                http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
                http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd ">


          <http pattern="/oauth/token" create-session="stateless"  authentication-manager-ref="authenticationManager"
                xmlns="http://www.springframework.org/schema/security" > 

                <intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" method="POST" />
                <anonymous enabled="false" />
                <http-basic entry-point-ref="clientAuthenticationEntryPoint" />
                <custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER" /> 
                <access-denied-handler ref="oauthAccessDeniedHandler" />
          </http>

          <http pattern="/protected/**" create-session="never" entry-point-ref="oauthAuthenticationEntryPoint"
                xmlns="http://www.springframework.org/schema/security">
                <anonymous enabled="false" />
                <intercept-url pattern="/protected/**" method="GET" access="ROLE_APP" />
                <!-- <intercept-url pattern="/resources/**" access="IS_AUTHENTICATED_FULLY" /> -->
                <custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
                <access-denied-handler ref="oauthAccessDeniedHandler" />
          </http>

          <http pattern="/logout" create-session="never" 
                entry-point-ref="oauthAuthenticationEntryPoint"
                xmlns="http://www.springframework.org/schema/security">
                <anonymous enabled="false" />
                <intercept-url pattern="/logout" method="GET" />
                <sec:logout invalidate-session="true" logout-url="/logout" success-handler-ref="logoutSuccessHandler"   />
                <custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
                <access-denied-handler ref="oauthAccessDeniedHandler" />
          </http>

          <bean id="logoutSuccessHandler" class="com.example.myproject.security.LogoutImpl" >
                <property name="tokenstore" ref="tokenStore"></property>
          </bean>

          <bean id="oauthAuthenticationEntryPoint"
                class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
                <property name="exceptionTranslator" ref="myExceptionTranslator"></property>
          </bean>

      <bean id="myExceptionTranslator"
                class="org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator">
          </bean>

          <bean id="clientAuthenticationEntryPoint"
                class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
                <property name="realmName" value="springsec/client" />
                <property name="typeName" value="Basic" />
          </bean>

          <bean id="oauthAccessDeniedHandler"
                class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler">
          </bean>

          <bean id="clientCredentialsTokenEndpointFilter"
                class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
                <property name="authenticationManager" ref="authenticationManager" />
          </bean>

          <authentication-manager alias="authenticationManager"
                xmlns="http://www.springframework.org/schema/security">
                <authentication-provider user-service-ref="clientDetailsUserService" />
          </authentication-manager>

          <bean id="clientDetailsUserService"
                class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
                <constructor-arg ref="clientDetails" />
          </bean>

          <bean id="clientDetails" class="com.example.myproject.service.ClientService"/>

          <authentication-manager id="userAuthenticationManager" 
                xmlns="http://www.springframework.org/schema/security">
                <authentication-provider  user-service-ref="userService">
                </authentication-provider>
          </authentication-manager>

          <bean id="userService"
                class="com.example.myproject.service.UserService">
          </bean>

          <oauth:authorization-server
                client-details-service-ref="clientDetails" token-services-ref="tokenServices">
                <oauth:authorization-code />
                <oauth:implicit/>
                <oauth:refresh-token/>
                <oauth:client-credentials />
                <oauth:password authentication-manager-ref="userAuthenticationManager"/>
          </oauth:authorization-server>

          <oauth:resource-server id="resourceServerFilter"
                resource-id="springsec" token-services-ref="tokenServices" />

          <!-- <bean id="tokenStore"
                class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" /> -->

          <bean id="tokenStore"
              class="org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore" >
                <property name="authenticationKeyGenerator">
                      <bean class="com.example.myproject.service.UniqueAuthenticationKeyGenerator" />
                </property> 
         </bean>

          <bean id="tokenServices" 
                class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
                <property name="tokenStore" ref="tokenStore" />
                <property name="supportRefreshToken" value="true" />
                <property name="accessTokenValiditySeconds" value="300000"></property>
                <property name="clientDetailsService" ref="clientDetails" />
                <property name="tokenEnhancer"><bean class="com.example.myproject.service.CustomTokenEnhancer" /></property>
          </bean>

          <sec:global-method-security
                pre-post-annotations="enabled" proxy-target-class="true">
                <!--you could also wire in the expression handler up at the layer of the 
                      http filters. See https://jira.springsource.org/browse/SEC-1452 -->
                <sec:expression-handler ref="oauthExpressionHandler" />
          </sec:global-method-security>

          <oauth:expression-handler id="oauthExpressionHandler" />
          <oauth:web-expression-handler id="oauthWebExpressionHandler" />

    </beans>

ClientService.java:

            @Component
    public class ClientService implements ClientDetailsService {

        @Autowired
        private OauthRepository oauthRepository;

        @Override
        public ClientDetails loadClientByClientId(String s) throws ClientRegistrationException{
            BaseClientDetails clientDetails = oauthRepository.getByClientId(s);
                  return clientDetails;

        }
    }

UserService.java:

            @Component
    public class UserService implements UserDetailsService {

        @Autowired
        private OauthRepository oauthRepository;

        @Override
        public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
          UserDetails user = oauthRepository.getByUsername(s);
                  return user;

        }
    }

OauthRepository.java:

            @Repository
    @Transactional
    public class OauthRepository {

          @Autowired
          private SessionFactory sessionFactory;

          @Autowired
          private InMemoryTokenStore tokenStore;

          private org.hibernate.Session getCurrentSession(){
                return sessionFactory.getCurrentSession();
          }



        public UserDetails getByUsername(String username) {

                MyUser user=new MyUser();
                user.setUserName(username);
                Query query=getCurrentSession().createQuery("FROM User WHERE userName=:usrName");
                query.setParameter("usrName", username);
                List<SiUser> getUser=query.list();

                User act=getUser.get(0);
                user.setPassword(act.getPassword());
                user.setUserId(act.getUserId());
                user.setAuthorities(getAuthorities(act.getUserId()));

                return user;
        }

        public BaseClientDetails getByClientId(String clientId) {
          System.out.println(" *** OauthRepository.getByClientId "+clientId);

          Query query=getCurrentSession().createQuery("FROM OauthClientDetails WHERE clientId=:clientId");
                query.setParameter("clientId", clientId);
                List<OauthClientDetails> getClient=query.list();

                OauthClientDetails oauthClient=getClient.get(0);
                BaseClientDetails details = new BaseClientDetails();
                details.setClientId(oauthClient.getClientId());
                List<String> grantTypesList = Arrays.asList(oauthClient.getAuthorizedGrantTypes().split(","));
                details.setAuthorizedGrantTypes(grantTypesList); 
                details.setClientSecret(oauthClient.getClientSecret());

            return details;


        }

    /**
     * Retrieves a collection of {@link GrantedAuthority} based on a numerical role
     * @param role the numerical role
     * @return a collection of {@link GrantedAuthority
     */
    public Collection<GrantedAuthority> getAuthorities(Integer role) {
          List<GrantedAuthority> authList = getGrantedAuthorities(getRoles(role));
          return authList;
    }
    /**
     * Converts a numerical role to an equivalent list of roles
     * @param role the numerical role
     * @return list of roles as as a list of {@link String}
     */
    public List<String> getRoles(Integer role) {
          List<String> roles = new ArrayList<String>();

          Query query=getCurrentSession().createQuery("FROM UserRole WHERE userID=:userId");
          query.setParameter("userId", role);
          List<SiUserRole> getUser=query.list();

          UserRole actRole=getUser.get(0);
          roles.add(actRole.getRole());
          return roles;
    }
    /**
     * Wraps {@link String} roles to {@link SimpleGrantedAuthority} objects
     * @param roles {@link String} of roles
     * @return list of granted authorities
     */
    public static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) {
          List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
          for (String role : roles) {
                authorities.add(new GrantedAuthorityImpl(role));
          }
          return authorities;
    }


    }

servlet-context.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:context="http://www.springframework.org/schema/context"
          xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx"
          xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
      http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd
      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">
          <!-- @author Nagesh.Chauhan(neel4soft@gmail.com) -->
          <context:annotation-config />
        <context:component-scan base-package="com.example.myproject" />
          <mvc:annotation-driven />

          <bean id="multipartResolver"
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver">      

        <!-- one of the properties available; the maximum file size in bytes -->
         <property name="maxUploadSize" value="1000000000" />
          </bean>      

          <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/MyDatabase"/>
        <property name="username" value="username"/>
        <property name="password" value="password"/>
        <property name="validationQuery" value="SELECT 1"/>
      </bean>

      <!-- Hibernate Session Factory -->
      <bean id="mySessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="myDataSource"/>
        <property name="packagesToScan">
          <array>
            <value>com.example.myproject</value>
          </array>
        </property>
        <property name="hibernateProperties">
          <value>
            hibernate.dialect=org.hibernate.dialect.MySQLDialect
          </value>
        </property>
      </bean>
      <!-- Hibernate Transaction Manager -->
      <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="mySessionFactory"/>
      </bean>

      <!-- Activates annotation based transaction management -->
      <tx:annotation-driven transaction-manager="transactionManager"/>
    </beans>

0 个答案:

没有答案