Spring Security 入门详解(转)-阿里云开发者社区

开发者社区> 数据库> 正文
登录阅读全文

Spring Security 入门详解(转)

简介: 1.Spring Security介绍 Spring Security是基于spring的应用程序提供声明式安全保护的安全性框架,它提供了完整的安全性解决方案,能够在web请求级别和方法调用级别 处理身份证验证和授权.它充分使用了依赖注入和面向切面的技术.   Spring securi...

1.Spring Security介绍

Spring Security是基于spring的应用程序提供声明式安全保护的安全性框架,它提供了完整的安全性解决方案,能够在web请求级别和方法调用级别 处理身份证验证和授权.它充分使用了依赖注入和面向切面的技术.

  Spring security主要是从两个方面解决安全性问题:

  1. web请求级别:使用servlet过滤器保护web请求并限制URL级别的访问
  2. 方法调用级别:使用Spring AOP保护方法调用,确保具有适当权限的用户采用访问安全保护的方法.

2.Web请求级别的保护

  对于请求级别的安全性来说,主要时通过保护一个或多个URL,使得只有特定的用户才能访问,并其他用户访问该URL的内容.本文主要是基于spring mvc下整合Spring security模块.

2.1 声明代理Servlet过滤器

  在web中的URL的一般需要过滤器进行保护,所以需要借助一系列的Servlet过滤器提供各种各样的安全性功能.这也需要在web.xml中配置一系列相关的<filter>,使得配置文件臃肿难以阅读.所以Spring security提供了代理Servelt过滤器可以解决该问题.如下面清单所示:

1 <filter>
2     <filter-name>springSecurityFilterChain</filter-name>
3     <filter-class>
4         org.springframework.web.filter.DelegatingFilterProxy
5     </filter-class>
6 </filter>

  DelegatingFilterProxy是一个代理的Servelt过滤器,它主要负责将工作委托给一个javax.servlet.Filter实现类,这个实现类作为一个<bean>已经注册在Spring应用的上下文,且该bean的Id便是上面<filter-name>的名字,即springSecurityFilterChain.  

  springSecurityFilterChain,也可称为FilterChainProxy.它可以链接任意多个其他的过滤器,根据这些过滤器提供不同的安全特性.但是你并不需要在spring配置文件中配置该过滤器的bean和它所链接的其他过滤器

2.2 配置最小化web安全性和拦截请求

 1 <http auto-config="true">
 2     <intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
 3 </http>

   在spring的配置文件中加入这段代码可以拦截站点/admin分支行下的所有URL请求.并限制只有具备"ROLE_ADMIN"权限的用户才可以访问,"ROLE_ADMIN"是自定义的一个权限.pattern默认使用的是Ant格式。如果需要使用正则表达式则在http 元素的path-type设置为regex。<intercept-url>能够拦截请求,主要是对指定的URL进行保护,如果用户具有访问指定的URL的权限则通过否则拒绝。

  <http>元素将自动创建一个FilterChainProxy以及链中所有的过滤器bean.同时会将FilterChainProxy的bean托管给配置在web.xml的DelegatingFilterProxy.设置auto-config="true"会自动生成一个登陆界面,可以通过http://localhost:8080/你的项目名称/spring_security_login.设置为ture也等价于下面的配置:

复制代码
<http>
    <form-login />
  <!--HTTP 基本认证 -->
    <http-basic/>
  <!-- 可以通过logout-url属性设置用户退出的url-->
    <logout />
    <intercept pattern="/**" access="ROLE_DEMO" />
</http>
复制代码

  Spring security 3.0以后加入了对SpEL的支持,可以将<http>元素的use-expressions设置为"true"便可使用SpEL。

<http auto-config="true" use-expressions="true">
   ..
    <intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')">
</http>

  Spring Security 支持的所有SpEL表达式如下:

安全表达式  计算结果
authentication   用户认证对象
denyAll   结果始终为false
hasAnyRole(list of roles)   如果用户被授权指定的任意权限,结果为true
hasRole(role) 如果用户被授予了指定的权限,结果 为true
hasIpAddress(IP Adress) 用户地址
isAnonymous()   是否为匿名用户
isAuthenticated()   不是匿名用户
isFullyAuthenticated   不是匿名也不是remember-me认证
isRemberMe()   remember-me认证
permitAll 始终true
principal 用户主要信息对象

2.3 通过表单安全登陆

  虽然<http>元素设置auto-config="true",可以自动生成一个自动登陆页面。当一般开始都是采用自定义的登陆界面。所以需要进行下面配置:

<http auto-config="true">
    <!-- 设置登录页配置 login-page指定了登录界面的视图,authentication-failure-url则设置失败后的重定向到相同的登陆界面-->
    <from-login login-processing-url="/static/j_spring_security_check"
    login-page="/login" 
    authentication-failure-url="/login?login_error=t">
</http>

  在自定义的登录界面中将表单提交地址设置为"/static/j_spring_security_check",同时需要将用户名输入框和密码输入框name分别设置为j_username和j_password 。有些应用中往往会设置记住密码,方便用户访问应用,不需要每次都登录。实现该功能只需要在<http>元素中加入:

<!--key设置cookie的秘钥的值,默认是SpringSecured。后一个属性指定有效期  -->
<remember-me key="spitterKey" token-validity-seconds="2419200"/> 

 静态页面中加入:

<input  name="_spring_security_rember_me" type="checkbox"/>

2.4 强制请求使用https

  https传输数据比较安全,如将用户,密码提交可以使用https保证数据传输的安全。可以进行以下设置,保证每次对指定URL请求,Spring Security都会自动重定向为https请求。不管用户访问时是否加入https.

<intercept pattern="/admin/**" access="ROLE_DEMO" requires-channel="https" />

3. 保护视图

  Spring Security提供jsp标签库,支持视图级别的保护,这个标签库包含3个标签:

  1. <security:accesscontrollist> :如果认证用户具有权限列表中的某一个权限,那么这个标签范围的内容将显示。
  2. <security:authentication>: 访问当前用户认证对象的属性。一般用户显示当前用户的用户名之类的。具有的用户认证信息有:
  • authorities:一组用于用户所授予的GrantedAuthority对象
  • credentials:核实用户的凭据
  • detail:认证的附加信息(IP地址,会话ID等)
  • principal:用户的主要信息对象

  3.<security:authorize>: 如果当前用户满足特定全新,则显示标签范围的内容。例:

<!-- 显示用户信息, 并将信息复制给var变量,该变量的使用范围为scope的范围。var和scope可以不设置-->
 Hello <security:authentication property="principal.usrname" var="loginId" scope="request">
 <security:authorize access="hasRole('ROLE_ADMIN')">
    如果当前用户有ROLE_ADMIN权限,则显示这部分内容
</security:authorize>

<security:authorize>除了使用access来指定权限外还可以根据url设置具体权限,即在拦截请求中指定的url的权限。

<security:authorize url="/admin/**">
    如果当前用户有/admin/**对应的权限,则显示这部分内容
</security:authorize>
4.认证用户  前面提到很多用户对象和用户权限的问题,他们的关系和定义就是通过认证用户来定义的。 Spring Security提供了以下认证策略:
  • 内存用户存储库,即显示的配置在spring配置文件中。
  • 基于jdbc的用户存储库
  • 基于LDAP的用户存储库
  • OpenID 分散式用户身份识别系统
  • 中心认证服务(CAS)
  • X.509证书
  • 基于JAAS的提供者

  这里主要是介绍基于spirng配置和jdbc的。

4.1 配置内存用户存储库

首先建立一个用户服务,配置所有用户和权限信息。然后交给认证管理器管理,认证管理器会将认证的任务交给一个或多个认证提供者。

复制代码
<!-- 用户服务-->
<user-service id="userService">
    <user name="alibaba" password="123456" authorities="ROLE_ADMIN">
    <user name="baidu" password="66666" authorities="ROLE_BAIDU">
    ......
</user-service>
<!-- 认证管理器-->
<authentication-manager>
    <authentication-provider user-service-ref="userService"/>
</authentication-manager>
复制代码

  另一种方式将认证提供者和用户服务装配在一起,适用于只有一种用户服务:  

复制代码
<!-- 认证提供者-->
<authentication-provider>
    <!-- 用户服务-->
<user-service id="userService">
    <user name="alibaba" password="123456" authorities="ROLE_ADMIN">
    <user name="baidu" password="66666" authorities="ROLE_BAIDU">
    ......
</user-service>
</authentication-provider>
复制代码

4.2 基于数据库进行认证

    这个是最常用的是用户认证,因为很多应用都是采用数据库存储用户数据。Spring Security提供了<jdbc-usr-service>.如果只指定了  data-source-ref得数据源,那么spring security会自己为我们写sql语句从数据库中查找用户和权限信息。但一般情况下,提供的查询语句并不能和我们的数据库对应上,所以我们需要自己写sql语句。主要包括以下属性:

  • users-by-username-query:根据用户名查询用户名,密码以及是否可用状态
  • authorities-by-username-query:根据用户名查询用户被用户名和授权的权限。
  • group-authorities-by-username-query:根据用户名查询用户组的权限。  
<jdbc-user-service id="userService"  data-source-ref="dataSource"
      users-by-username="select username,password, true from user where username=?"
      authories-by-username-query="select username,role from user_role where username=?" />  
<authentication-manager>
    <authentication-provider user-service-ref="userService"/>
</authentication-manager>

5.保护方法调用

  spring security的方法级别的保护是基于Spring AOP技术。首先需要在spring配置文件中加以下配置,才能使spring Security保护那些使用相关注解的方法。

<global-method-security secured-annotations="enabled" />

  spring Security支持4种方法级别安全性的方法:

  1. 使用@Secured注解方法,这是spring自带的注解方法。@Secured("")内部的字符串不具有SpEL特性,只能是具体的权限。
  2. 使用@JSR-250 @RelosAllowed注解的方法。作用和使用方法与@Secured一样,不同在于它不是spring框架的,所以可以做到和spring框架的解耦。
  3. 使用Spring 方法调用前和调用后注解方法。这些方法支持SpEL.
  4. 匹配一个或多个明确声明的切点方法。

5.1 @Secured和 @RelosAllowed

复制代码
@Secured("ROLE_ADMIN")
public void addUser(User user){
    ...  
}
@RolesAllowed("ROLE_ADMIN")
public void updateUser(User user){
    ...  
}
复制代码

5.2 使用Spring 方法调用前和调用后注解方法

 可以使用SpEL方法有四种:

  1. @PreAuthorize: 在方法调用前,基于表达式计算结果来限制方法访问
  2. @PostAuthorize: 允许方法调用,但是如果表达式结果为fasle则抛出异常
  3. @PostFilter :允许方法调用,但必须按表达式过滤方法结果。
  4. @PreFilter:允许方法调用,但必须在进入方法前过滤输入值
复制代码
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void addUser(User user){
   //如果具有权限 ROLE_ADMIN 访问该方法
    ....
}

//returnObject可以获取返回对象user,判断user属性username是否和访问该方法的用户对象的用户名一样。不一样则抛出异常。
@PostAuthorize("returnObject.user.username==principal.username")
public User getUser(int userId){
   //允许进入
...
    return user;    
}

//将结果过滤,即选出性别为男的用户
@PostFilter("returnObject.user.sex=='男' ")
public List<User> getUserList(){
   //允许进入
...
    return user;    
}
复制代码

5.3 匹配一个或多个明确声明的切点方法

    为多个方法设置相同的授权检查,spring security提供了 <protect-pointcut>元素。配置如下:

<global-method-security secured-annotations="enabled" >
    <protect-pointcut access="ROLE_ADMIN" expression="execution(@com.securitytest.service.UserService**.*(String)"
</global-method-security>

http://www.cnblogs.com/jaylon/p/4905769.html

Remember-Me功能

 

目录

 

1.1     概述

1.2     基于简单加密token的方法

1.3     基于持久化token的方法

1.4     Remember-Me相关接口和实现类

1.4.1    TokenBasedRememberMeServices

1.4.2    PersistentTokenBasedRememberMeServices

 

1.1          概述

       Remember-Me是指网站能够在Session之间记住登录用户的身份,具体来说就是我成功认证一次之后在一定的时间内我可以不用再输入用户名和密码进行登录了,系统会自动给我登录。这通常是通过服务端发送一个cookie给客户端浏览器,下次浏览器再访问服务端时服务端能够自动检测客户端的cookie,根据cookie值触发自动登录操作。Spring Security为这些操作的发生提供必要的钩子,并且针对于Remember-Me功能有两种实现。一种是简单的使用加密来保证基于cookie的token的安全,另一种是通过数据库或其它持久化存储机制来保存生成的token。

       需要注意的是两种实现都需要一个UserDetailsService。如果你使用的AuthenticationProvider不使用UserDetailsService,那么记住我将会不起作用,除非在你的ApplicationContext中拥有一个UserDetailsService类型的bean。

 

1.2          基于简单加密token的方法

       当用户选择了记住我成功登录后,Spring Security将会生成一个cookie发送给客户端浏览器。cookie值由如下方式组成:

base64(username+":"+expirationTime+":"+md5Hex(username+":"+expirationTime+":"+password+":"+key))

  • username:登录的用户名。
  • password:登录的密码。
  • expirationTime:token失效的日期和时间,以毫秒表示。
  • key:用来防止修改token的一个key。

       这样用来实现Remember-Me功能的token只能在指定的时间内有效,且必须保证token中所包含的username、password和key没有被改变才行。需要注意的是,这样做其实是存在安全隐患的,那就是在用户获取到实现记住我功能的token后,任何用户都可以在该token过期之前通过该token进行自动登录。如果用户发现自己的token被盗用了,那么他可以通过改变自己的登录密码来立即使其所有的记住我token失效。如果希望我们的应用能够更安全一点,可以使用接下来要介绍的持久化token方式,或者不使用Remember-Me功能,因为Remember-Me功能总是有点不安全的。

       使用这种方式时,我们只需要在http元素下定义一个remember-me元素,同时指定其key属性即可。key属性是用来标记存放token的cookie的,对应上文提到的生成token时的那个key。

   <security:http auto-config="true">

      <security:form-login/>

      <!-- 定义记住我功能 -->

      <security:remember-me key="elim"/>

      <security:intercept-url pattern="/**" access="ROLE_USER" />

   </security:http>

 

       这里有两个需要注意的地方。第一,如果你的登录页面是自定义的,那么需要在登录页面上新增一个名为“_spring_security_remember_me”的checkbox,这是基于NameSpace定义提供的默认名称,如果要自定义可以自己定义TokenBasedRememberMeServices或PersistentTokenBasedRememberMeServices对应的bean,然后通过其parameter属性进行指定,具体操作请参考后文关于《Remember-Me相关接口和实现类》部分内容。第二,上述功能需要一个UserDetailsService,如果在你的ApplicationContext中已经拥有一个了,那么Spring Security将自动获取;如果没有,那么当然你需要定义一个;如果拥有在ApplicationContext中拥有多个UserDetailsService定义,那么你需要通过remember-me元素的user-service-ref属性指定将要使用的那个。如:

   <security:http auto-config="true">

      <security:form-login/>

      <!-- 定义记住我功能,通过user-service-ref指定将要使用的UserDetailsService-->

      <security:remember-me key="elim" user-service-ref="userDetailsService"/>

      <security:intercept-url pattern="/**" access="ROLE_USER" />

   </security:http>

  

   <bean id="userDetailsService"class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">

      <property name="dataSource" ref="dataSource"/>

   </bean>

 

1.3          基于持久化token的方法

       持久化token的方法跟简单加密token的方法在实现Remember-Me功能上大体相同,都是在用户选择了“记住我”成功登录后,将生成的token存入cookie中并发送到客户端浏览器,待到下次用户访问系统时,系统将直接从客户端cookie中读取token进行认证。所不同的是基于简单加密token的方法,一旦用户登录成功后,生成的token将在客户端保存一段时间,如果用户不点击退出登录,或者不修改密码,那么在cookie失效之前,他都可以使用该token进行登录,哪怕该token被别人盗用了,用户与盗用者都同样可以进行登录。而基于持久化token的方法采用这样的实现逻辑:

       (1)用户选择了“记住我”成功登录后,将会把username、随机产生的序列号、生成的token存入一个数据库表中,同时将它们的组合生成一个cookie发送给客户端浏览器。

       (2)当下一次没有登录的用户访问系统时,首先检查cookie,如果对应cookie中包含的username、序列号和token与数据库中保存的一致,则表示其通过验证,系统将重新生成一个新的token替换数据库中对应组合的旧token,序列号保持不变,同时删除旧的cookie,重新生成包含新生成的token,就的序列号和username的cookie发送给客户端。

       (3)如果检查cookie时,cookie中包含的username和序列号跟数据库中保存的匹配,但是token不匹配。这种情况极有可能是因为你的cookie被人盗用了,由于盗用者使用你原本通过认证的cookie进行登录了导致旧的token失效,而产生了新的token。这个时候Spring Security就可以发现cookie被盗用的情况,它将删除数据库中与当前用户相关的所有token记录,这样盗用者使用原有的cookie将不能再登录,同时提醒用户其帐号有被盗用的可能性。

       (4)如果对应cookie不存在,或者包含的username和序列号与数据库中保存的不一致,那么将会引导用户到登录页面。

       从以上逻辑我们可以看出持久化token的方法比简单加密token的方法更安全,因为一旦你的cookie被人盗用了,你只要再利用原有的cookie试图自动登录一次,原有的token将失效导致盗用者不能再使用原来盗用的cookie进行登录了,同时用户可以发现自己的cookie有被盗用的可能性。但因为cookie被盗用后盗用者还可以在用户下一次登录前顺利的进行登录,所以如果你的应用对安全性要求比较高就不要使用Remember-Me功能了。

    使用持久化token方法时需要我们的数据库中拥有如下表及其表结构。

create table persistent_logins (username varchar(64) not null,

                                    series varchar(64) primary key,

                                    token varchar(64) not null,

                                    last_used timestamp not null)

 

    然后还是通过remember-me元素来使用,只是这个时候我们需要其data-source-ref属性指定对应的数据源,同时别忘了它也同样需要ApplicationContext中拥有UserDetailsService,如果拥有多个,请使用user-service-ref属性指定remember-me使用的是哪一个。

   <security:http auto-config="true">

      <security:form-login/>

      <!-- 定义记住我功能 -->

      <security:remember-me data-source-ref="dataSource"/>

      <security:intercept-url pattern="/**" access="ROLE_USER" />

   </security:http>

 

1.4     Remember-Me相关接口和实现类

在上述介绍中,我们实现Remember-Me功能是通过Spring Security为了简化Remember-Me而提供的NameSpace进行定义的。而底层实际上还是通过RememberMeServices、UsernamePasswordAuthenticationFilter和RememberMeAuthenticationFilter的协作来完成的。RememberMeServices是Spring Security为Remember-Me提供的一个服务接口,其定义如下。

publicinterface RememberMeServices {

    /**

     * 自动登录。在实现这个方法的时候应该判断用户提供的Remember-Me cookie是否有效,如果无效,应当直接忽略。

     * 如果认证成功应当返回一个AuthenticationToken,推荐返回RememberMeAuthenticationToken;

     * 如果认证不成功应当返回null。

     */

    Authentication autoLogin(HttpServletRequest request, HttpServletResponse response);

    /**

     * 在用户登录失败时调用。实现者应当做一些类似于删除cookie之类的处理。

     */

    void loginFail(HttpServletRequest request, HttpServletResponse response);

    /**

     * 在用户成功登录后调用。实现者可以在这里判断用户是否选择了“Remember-Me”登录,然后做相应的处理。

     */

    void loginSuccess(HttpServletRequest request, HttpServletResponse response,

        Authentication successfulAuthentication);

}

 

       UsernamePasswordAuthenticationFilter拥有一个RememberMeServices的引用,默认是一个空实现的NullRememberMeServices,而实际当我们通过remember-me定义启用Remember-Me时,它会是一个具体的实现。用户的请求会先通过UsernamePasswordAuthenticationFilter,如认证成功会调用RememberMeServices的loginSuccess()方法,否则调用RememberMeServices的loginFail()方法。UsernamePasswordAuthenticationFilter是不会调用RememberMeServices的autoLogin()方法进行自动登录的。之后运行到RememberMeAuthenticationFilter时如果检测到还没有登录,那么RememberMeAuthenticationFilter会尝试着调用所包含的RememberMeServices的autoLogin()方法进行自动登录。关于RememberMeServices Spring Security已经为我们提供了两种实现,分别对应于前文提到的基于简单加密token和基于持久化token的方法。

 

1.4.1   TokenBasedRememberMeServices

       TokenBasedRememberMeServices对应于前文介绍的使用namespace时基于简单加密token的实现。TokenBasedRememberMeServices会在用户选择了记住我成功登录后,生成一个包含token信息的cookie发送到客户端;如果用户登录失败则会删除客户端保存的实现Remember-Me的cookie。需要自动登录时,它会判断cookie中所包含的关于Remember-Me的信息是否与系统一致,一致则返回一个RememberMeAuthenticationToken供RememberMeAuthenticationProvider处理,不一致则会删除客户端的Remember-Me cookie。TokenBasedRememberMeServices还实现了Spring Security的LogoutHandler接口,所以它可以在用户退出登录时立即清除Remember-Me cookie。

 

       如果把使用namespace定义Remember-Me改为直接定义RememberMeServices和对应的Filter来使用的话,那么我们可以如下定义。

   <security:http>

      <security:form-login login-page="/login.jsp"/>

      <security:intercept-url pattern="/login*.jsp*"access="IS_AUTHENTICATED_ANONYMOUSLY"/>

      <security:intercept-url pattern="/**" access="ROLE_USER" />

      <!-- 把usernamePasswordAuthenticationFilter加入FilterChain -->

      <security:custom-filter ref="usernamePasswordAuthenticationFilter"before="FORM_LOGIN_FILTER"/>

      <security:custom-filter ref="rememberMeFilter" position="REMEMBER_ME_FILTER"/>

   </security:http>

   <!-- 用于认证的AuthenticationManager -->

   <security:authentication-manager alias="authenticationManager">

      <security:authentication-provider

         user-service-ref="userDetailsService"/>

      <security:authentication-provider ref="rememberMeAuthenticationProvider"/>

   </security:authentication-manager>

 

   <bean id="userDetailsService"

      class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">

      <property name="dataSource" ref="dataSource" />

   </bean>

 

   <bean id="usernamePasswordAuthenticationFilter"class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">

      <property name="rememberMeServices" ref="rememberMeServices"/>

      <property name="authenticationManager" ref="authenticationManager"/>

      <!-- 指定request中包含的用户名对应的参数名 -->

      <property name="usernameParameter" value="username"/>

      <property name="passwordParameter" value="password"/>

      <!-- 指定登录的提交地址 -->

      <property name="filterProcessesUrl" value="/login.do"/>

   </bean>

   <!-- Remember-Me对应的Filter -->

   <bean id="rememberMeFilter"

   class="org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">

      <property name="rememberMeServices" ref="rememberMeServices" />

      <property name="authenticationManager" ref="authenticationManager" />

   </bean>

   <!-- RememberMeServices的实现 -->

   <bean id="rememberMeServices"

   class="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">

      <property name="userDetailsService" ref="userDetailsService" />

      <property name="key" value="elim" />

      <!-- 指定request中包含的用户是否选择了记住我的参数名 -->

      <property name="parameter" value="rememberMe"/>

   </bean>

   <!-- key值需与对应的RememberMeServices保持一致 -->

   <bean id="rememberMeAuthenticationProvider"

   class="org.springframework.security.authentication.RememberMeAuthenticationProvider">

      <property name="key" value="elim" />

   </bean>

 

       需要注意的是RememberMeAuthenticationProvider在认证RememberMeAuthenticationToken的时候是比较它们拥有的key是否相等,而RememberMeAuthenticationToken的key是TokenBasedRememberMeServices提供的,所以在使用时需要保证RememberMeAuthenticationProvider和TokenBasedRememberMeServices的key属性值保持一致。需要配置UsernamePasswordAuthenticationFilter的rememberMeServices为我们定义好的TokenBasedRememberMeServices,把RememberMeAuthenticationProvider加入AuthenticationManager的providers列表,并添加RememberMeAuthenticationFilter和UsernamePasswordAuthenticationFilter到FilterChainProxy。

 

1.4.2   PersistentTokenBasedRememberMeServices

       PersistentTokenBasedRememberMeServices是RememberMeServices基于前文提到的持久化token的方式实现的。具体实现逻辑跟前文介绍的以NameSpace的方式使用基于持久化token的Remember-Me是一样的,这里就不再赘述了。此外,如果单独使用,其使用方式和上文描述的TokenBasedRememberMeServices是一样的,这里也不再赘述了。

       需要注意的是PersistentTokenBasedRememberMeServices是需要将token进行持久化的,所以我们必须为其指定存储token的PersistentTokenRepository。Spring Security对此有两种实现,InMemoryTokenRepositoryImpl和JdbcTokenRepositoryImpl。前者是将token存放在内存中的,通常用于测试,而后者是将token存放在数据库中。PersistentTokenBasedRememberMeServices默认使用的是前者,我们可以通过其tokenRepository属性来指定使用的PersistentTokenRepository。

       使用JdbcTokenRepositoryImpl时我们可以使用在前文提到的默认表结构。如果需要使用自定义的表,那么我们可以对JdbcTokenRepositoryImpl进行重写。定义JdbcTokenRepositoryImpl时需要指定一个数据源dataSource,同时可以通过设置参数createTableOnStartup的值来控制是否要在系统启动时创建对应的存入token的表,默认创建语句为“create table persistent_logins (username varchar(64) not null, series varchar(64) primary key, token varchar(64) not null, last_used timestamp not null)”,但是如果自动创建时对应的表已经存在于数据库中,则会抛出异常。createTableOnStartup属性默认为false。

       直接显示地使用PersistentTokenBasedRememberMeServices和上文提到的直接显示地使用TokenBasedRememberMeServices的方式是一样的,我们只需要将上文提到的配置中RememberMeServices实现类TokenBasedRememberMeServices换成PersistentTokenBasedRememberMeServices即可。

   <!-- RememberMeServices的实现 -->

   <bean id="rememberMeServices"

   class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices">

      <property name="userDetailsService" ref="userDetailsService" />

      <property name="key" value="elim" />

      <!-- 指定request中包含的用户是否选择了记住我的参数名 -->

      <property name="parameter" value="rememberMe"/>

      <!-- 指定PersistentTokenRepository -->

      <property name="tokenRepository">

         <beanclass="org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl">

            <!-- 数据源 -->

            <property name="dataSource" ref="dataSource"/>

            <!-- 是否在系统启动时创建持久化token的数据库表 -->

            <property name="createTableOnStartup" value="false"/>

         </bean>

      </property>

   </bean>

 

(注:本文是基于Spring Security3.1.6所写)

(注:原创文章,转载请注明出处。原文地址:http://elim.iteye.com/blog/2163997

http://elim.iteye.com/blog/2163997

 

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
数据库
使用钉钉扫一扫加入圈子
+ 订阅

分享数据库前沿,解构实战干货,推动数据库技术变革

其他文章