Maven搭建Spring Security3.2项目详解

原文:http://blog.csdn.net/fengshizty/article/details/43732815

前言

        本来是打算在上一篇SpringMVC+Hibernate上写的,结果发现上面那篇一起整合的,结果发现上一篇内容实在是太长了,就另起一篇,这篇主要是采用 Maven搭建Spring+SpringMVC+Hibernate+Security整合,而Spring+SpringMVC+Hibernate已经在上一篇介绍了,在这篇将不再重复写了,主要说明一下SpringSecurity3.2权限控制整合搭建,以及配置,使用注意事项等。

        SpringSecurity的Api文档地址:查看

1、Maven映入SpringSecurity依赖包

      在pom.xml中引入我们需要引入spring-security-core,spring-security-config,spring-security-taglibs三个包,如下

    

[html]  view plain copy
  1.              <!-- spring-security -->  
  2. <dependency>  
  3.     <groupId>org.springframework.security</groupId>  
  4.     <artifactId>spring-security-core</artifactId>  
  5.     <version>${security.version}</version>  
  6. </dependency>  
  7.   
  8. <dependency>  
  9.     <groupId>org.springframework.security</groupId>  
  10.     <artifactId>spring-security-config</artifactId>  
  11.     <version>${security.version}</version>  
  12. </dependency>  
  13.   
  14. <dependency>  
  15.     <groupId>org.springframework.security</groupId>  
  16.     <artifactId>spring-security-taglibs</artifactId>  
  17.     <version>${security.version}</version>  
  18. </dependency>  

2、配置security的配置文件

      我们新建一个配置文件(起名随意),我这儿就叫spring-security.xml,我现在定义了几个权限,权限信息表内容如下:

     Maven搭建Spring Security3.2项目详解_第1张图片

  其中:管理用户和全部用户的权限将通过jsp中security标签配置,其他的通过spring-security.xml文件配置。

  先贴出spring-security.xml的文件,详细配置含义我将做一个简单的说明:

    

[html]  view plain copy
  1. <span style="font-size:14px;"><?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:security="http://www.springframework.org/schema/security"  
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  5.     xsi:schemaLocation="http://www.springframework.org/schema/beans   
  6.                         http://www.springframework.org/schema/beans/spring-beans-4.1.xsd  
  7.                         http://www.springframework.org/schema/security   
  8.                         http://www.springframework.org/schema/security/spring-security-3.2.xsd"  
  9.     default-lazy-init="true">  
  10.   
  11.     <description>spring-security配置</description>  
  12.   
  13.     <!-- 静态资源 -->  
  14.     <security:http pattern="/css/**" security="none" />  
  15.     <security:http pattern="/js/**" security="none" />  
  16.     <security:http pattern="/images/**" security="none" />  
  17.   
  18.     <security:http>  
  19.         <security:intercept-url pattern="/user/save*"  
  20.             access="ROLE_添加用户" requires-channel="any" />  
  21.         <security:intercept-url pattern="/user/delete*"  
  22.             access="ROLE_删除用户" requires-channel="any" />  
  23.         <security:intercept-url pattern="/user/user*"  
  24.             access="ROLE_浏览用户" requires-channel="any" />  
  25.         <security:intercept-url pattern="/user/update*"  
  26.             access="ROLE_修改用户" requires-channel="any" />  
  27.   
  28.         <security:session-management>  
  29.             <security:concurrency-control  
  30.                 expired-url="/login/login.htmls?repeat=true" max-sessions="1"  
  31.                 error-if-maximum-exceeded="true" />  
  32.         </security:session-management>  
  33.   
  34.         <security:form-login login-page="/login/login.htmls"  
  35.             authentication-failure-url="/login/login.htmls?error=true"  
  36.             default-target-url="/user/main.htmls" always-use-default-target='true'  
  37.             username-parameter="nickName" password-parameter="nickPassword" />  
  38.   
  39.         <security:logout invalidate-session="true"  
  40.             logout-success-url="/login/login.htmls?logout=true" />  
  41.   
  42.     </security:http>  
  43.   
  44.     <!-- 认证配置 自定义认证实现UserDetailsService接口 -->  
  45.     <security:authentication-manager>  
  46.         <security:authentication-provider  
  47.             user-service-ref="userDetailsService">  
  48.             <!-- 配置密码加密方式 -->  
  49.             <security:password-encoder hash="md5" />  
  50.         </security:authentication-provider>  
  51.     </security:authentication-manager>  
  52.   
  53.     <bean id="userDetailsService" class="org.andy.work.service.impl.UserDetailsServiceImpl" />  
  54.       
  55. </beans></span>  

  其中:我们配置了静态文件管理,session对话管理,登录管理,注销配置,权限配置,自定义数据表权限认证配置。

2.1、静态文件管理

    我们对于css,image,js这些不用权限拦截。

2.2、session对话管理

   session管理max-sessions="1"配置了最多有一个用户登录,(在wab.xml还要添加如下:)

         

[html]  view plain copy
  1. <span style="font-size:14px;"><!-- spring-security 管理session配置 -->  
  2.     <listener>  
  3.         <listener-class>  
  4.             org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>  
  5.     </listener></span>  

    error-if-maximum-exceeded="true"  值为true时,若果有一个用户登录,第二个用户无法登陆,

                                                                  值为false时,若果有一个用户已经登录,下一个用户登录将踢掉上一个用户。

    自然在session-manager中我们可以配置session失效时,跳转的url如,invalid-session-url="/invalidSession.jsp",如果session失效时,刷新将跳转到invalidSession.jsp页面。

2.3、登录管理

    通过security:form-login配置登录,login-page为登录跳转的url,authentication-failure-url为登录失败时的url(次url可以不存在),

   username-parameter和password-parameter为登录表单是用户名和密码,如果不写默认为j_password和j_username

   login-processing-url:为登录时表单action跳转的url,如果不填写默认为 j_spring_security_check。

2.4、注销管理

   通过security:logout标签配置注销,invalidate-session:注销时session是否失效。logout-success-url:注销成功后跳转的地址。

logout-url:为注销的url,如果不填写,则默认为j_spring_security_logout

2.5、权限配置

   security:intercept-url为要拦截权限认证的的url,pattern为拦截的正则匹配url,access:所需的权限,可以是一个权限组,用逗号隔开,requires-channel:拦截http还是https的,如果两个都拦截用any。

2.6、配置自定义的权限认证机制

    通过我们数据库的权限表信息,我们自定义权限认证机制,需要我们实现UserDetailsService接口,配置用户密码的加密方式。

security:password-encoder:配置密码加密规则。

3、web.xml容器配置

   

[html]  view plain copy
  1. <span style="font-size:14px;">         <context-param>  
  2.         <param-name>contextConfigLocation</param-name>  
  3.         <param-value>  
  4.             classpath:spring.xml  
  5.             classpath:spring-hibernate.xml  
  6.             classpath:spring-security.xml  
  7.         </param-value>  
  8.     </context-param>  
  9.   
  10.        <!-- Spring-Security filter 最好配置在控制层filter的前面 -->  
  11.     <filter>  
  12.         <filter-name>springSecurityFilterChain</filter-name>  
  13.         <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
  14.     </filter>  
  15.     <filter-mapping>  
  16.         <filter-name>springSecurityFilterChain</filter-name>  
  17.         <url-pattern>/*</url-pattern>  
  18.     </filter-mapping>  
  19.   
  20.     <!-- spring-security 管理session配置 -->  
  21.     <listener>  
  22.         <listener-class>  
  23.             org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>  
  24.     </listener></span>  
 

配置了加载的spring-security文件,security拦截的filter,以及security的session监听。

4、自定义认证,实现UserDetailsService接口

UserDetailsServiceImpl如下:

[html]  view plain copy
  1. <span style="font-size:14px;">package org.andy.work.service.impl;  
  2.   
  3. import java.util.HashSet;  
  4. import java.util.Set;  
  5.   
  6. import org.andy.work.dao.UserDao;  
  7. import org.andy.work.entity.AcctAuthority;  
  8. import org.andy.work.entity.AcctRole;  
  9. import org.andy.work.entity.AcctUser;  
  10. import org.apache.log4j.Logger;  
  11. import org.springframework.beans.factory.annotation.Autowired;  
  12. import org.springframework.security.core.GrantedAuthority;  
  13. import org.springframework.security.core.authority.SimpleGrantedAuthority;  
  14. import org.springframework.security.core.userdetails.User;  
  15. import org.springframework.security.core.userdetails.UserDetails;  
  16. import org.springframework.security.core.userdetails.UserDetailsService;  
  17. import org.springframework.security.core.userdetails.UsernameNotFoundException;  
  18.   
  19. /**  
  20.  * 创建时间:2015-2-9 下午5:24:44  
  21.  *   
  22.  * @author andy  
  23.  * @version 2.2  
  24.  *          <p>  
  25.  *          描述: 实现SpringSecurity的UserDetails接口 自定义认证  
  26.  */  
  27.   
  28. public class UserDetailsServiceImpl implements UserDetailsService {  
  29.   
  30.     private static final Logger LOGGER = Logger  
  31.             .getLogger(UserDetailsServiceImpl.class);  
  32.   
  33.     // 注入查询User的dao层  
  34.     @Autowired  
  35.     private UserDao userDao;  
  36.   
  37.     @Override  
  38.     public UserDetails loadUserByUsername(String username)  
  39.             throws UsernameNotFoundException {  
  40.         LOGGER.info("认证用户:" + username);  
  41.   
  42.         // 查询数据库获取改用户的信息  
  43.         AcctUser acctUser = userDao.findByNickName(username);  
  44.   
  45.         if (null == acctUser) {  
  46.             throw new UsernameNotFoundException("用户:" + username + "不存在");  
  47.         }  
  48.   
  49.         Set<GrantedAuthority> authorities = getAuthorities(acctUser);  
  50.   
  51.         // 将没有使用到的属性设置为true  
  52.         UserDetails userDetails = new User(acctUser.getNickName(),  
  53.                 acctUser.getNickPassword(), true, true, true, true, authorities);  
  54.   
  55.         return userDetails;  
  56.     }  
  57.   
  58.     // 获得用户所有角色的权限  
  59.     private Set<GrantedAuthority> getAuthorities(AcctUser acctUser) {  
  60.         Set<GrantedAuthority> authoritySet = new HashSet<GrantedAuthority>();  
  61.   
  62.         // 默认所有的用户有"浏览用户"的权利  
  63.         authoritySet.add(new SimpleGrantedAuthority("ROLE_浏览用户"));  
  64.   
  65.         // 依次添加  
  66.         if (null != acctUser.getAcctRoles()  
  67.                 && acctUser.getAcctRoles().size() > 0)  
  68.             for (AcctRole role : acctUser.getAcctRoles()) {  
  69.                 if (null != role.getAcctAuthorities()  
  70.                         && role.getAcctAuthorities().size() > 0)  
  71.                     for (AcctAuthority authority : role.getAcctAuthorities()) {  
  72.                         authoritySet.add(new SimpleGrantedAuthority(authority  
  73.                                 .getPrefixedName()));  
  74.                     }  
  75.             }  
  76.   
  77.         return authoritySet;  
  78.     }  
  79.   
  80. }  
  81. </span>  

涉及到的AcctUser,AcctRole,AcctAuthority类我就不贴了,不然一大把,我会提供源码。

5、Security的认证错误提示

    我们可以通过sessionScope.SPRING_SECURITY_LAST_EXCEPTION.message获取认证错误。

6、Security获取session中的用户名和用户信息

     security将用户信息存放在session中,可以通过以下两种获得:

6.1、后台获取

    

[java]  view plain copy
  1. <span style="font-size:14px;">        //获取security的上下文  
  2.         SecurityContext securityContext = SecurityContextHolder.getContext();  
  3.         //获取认证对象  
  4.         Authentication authentication = securityContext.getAuthentication();  
  5.         //在认证对象中获取主体对象  
  6.         Object principal = authentication.getPrincipal();  
  7.           
  8.         String username = "";  
  9.         if(principal instanceof UserDetails){  
  10.             username = ((UserDetails) principal).getUsername();  
  11.         }else {  
  12.             username = principal.toString();  
  13.         }</span>  

6.1、前台获取

    先引入security的标签库:

[html]  view plain copy
  1. <span style="font-size:14px;"><%@taglib prefix="security" uri="http://www.springframework.org/security/tags"%></span>  

在查看:
[html]  view plain copy
  1. <span style="font-size:14px;"><security:authentication property="name"/></span>  

7、前台标签授权

    通过security:authorize标签设置权限,其有三种属性分别如下:

        ifAnyGranted::只有当前用户拥有所指定的权限中的一个的时候,就能显示标签内部的内容(相当于“或”的关系)

          ifAllGranted:只有当前用户拥有所指定的权限时,才显示标签的内容(相当于“与”的关系)

          ifNotGranted:  没有指定的权限的时候,显示标签内容(相当于“非”的关系)

自然也可以通过method限制是那种http的请求(http的请求有8种:- GET - DELETE - HEAD - OPTIONS    - POST     - PUT    - PATCH    - TRACE)。

8、后台Controller

LoginController

[java]  view plain copy
  1. <span style="font-size:14px;"><span style="font-size:14px;">package org.andy.work.controller;  
  2.   
  3. import org.andy.work.entity.AcctUser;  
  4. import org.apache.log4j.Logger;  
  5. import org.springframework.stereotype.Controller;  
  6. import org.springframework.validation.Errors;  
  7. import org.springframework.web.bind.annotation.ModelAttribute;  
  8. import org.springframework.web.bind.annotation.RequestMapping;  
  9. import org.springframework.web.bind.annotation.RequestParam;  
  10.   
  11. /** 
  12.  * 创建时间:2015-2-10 下午9:23:34 
  13.  *  
  14.  * @author andy 
  15.  * @version 2.2 描述: 
  16.  */  
  17. @Controller  
  18. @RequestMapping("/login")  
  19. public class LoginController {  
  20.   
  21.     private static final Logger LOGGER = Logger  
  22.             .getLogger(LoginController.class);  
  23.   
  24.     @RequestMapping("/login")  
  25.     public String login(@ModelAttribute AcctUser acctUser,  
  26.             @RequestParam(required = false) Boolean logout,  
  27.             Errors errors  
  28.             ) {  
  29.         LOGGER.info("login");  
  30.           
  31.         if(null != logout){  
  32.             errors.reject("msg""已经安全退出");  
  33.         }  
  34.           
  35.         return "/login/login";  
  36.     }  
  37.   
  38.   
  39. }</span>  
  40. </span>  

UserController类  
[java]  view plain copy
  1. <span style="font-size:14px;">package org.andy.work.controller;  
  2.   
  3. import java.util.List;  
  4.   
  5. import org.andy.work.entity.AcctUser;  
  6. import org.andy.work.service.UserService;  
  7. import org.apache.log4j.Logger;  
  8. import org.springframework.beans.factory.annotation.Autowired;  
  9. import org.springframework.security.core.Authentication;  
  10. import org.springframework.security.core.context.SecurityContext;  
  11. import org.springframework.security.core.context.SecurityContextHolder;  
  12. import org.springframework.security.core.userdetails.UserDetails;  
  13. import org.springframework.stereotype.Controller;  
  14. import org.springframework.ui.ModelMap;  
  15. import org.springframework.web.bind.annotation.PathVariable;  
  16. import org.springframework.web.bind.annotation.RequestMapping;  
  17. import org.springframework.web.bind.annotation.ResponseBody;  
  18.   
  19. /**   
  20.  * 创建时间:2015-2-7 上午11:49:00   
  21.  * @author andy   
  22.  * @version 2.2   
  23.  * 描述: 用户Controller 
  24.  */  
  25. @Controller  
  26. @RequestMapping("/user")  
  27. public class UserController {  
  28.   
  29.     private static final Logger LOGGER = Logger.getLogger(UserController.class);  
  30.       
  31.     @Autowired  
  32.     private UserService userService;  
  33.       
  34.     @RequestMapping("/showInfo/{userId}")  
  35.     public String showUserInfo(ModelMap modelMap, @PathVariable String userId){  
  36.         LOGGER.info("查询用户:" + userId);  
  37.         AcctUser userInfo = userService.load(userId);  
  38.         modelMap.addAttribute("userInfo", userInfo);  
  39.         return "/user/showInfo";  
  40.     }  
  41.       
  42.     @RequestMapping("/showInfos")  
  43.     public @ResponseBody List<AcctUser> showUserInfos(){  
  44.         LOGGER.info("查询用户全部用户");  
  45.         List<AcctUser> userInfos = userService.findAll();  
  46.         return userInfos;  
  47.     }  
  48.       
  49.       
  50.     @RequestMapping("/main")  
  51.     public String main(ModelMap modelMap){  
  52.         LOGGER.info("显示主页面");  
  53.         //后台获取security保存的session中的用户信息  
  54.           
  55.         //获取security的上下文  
  56.         SecurityContext securityContext = SecurityContextHolder.getContext();  
  57.         //获取认证对象  
  58.         Authentication authentication = securityContext.getAuthentication();  
  59.         //在认证对象中获取主体对象  
  60.         Object principal = authentication.getPrincipal();  
  61.           
  62.         String username = "";  
  63.         if(principal instanceof UserDetails){  
  64.             username = ((UserDetails) principal).getUsername();  
  65.         }else {  
  66.             username = principal.toString();  
  67.         }  
  68.         modelMap.addAttribute("username", username);  
  69.         return "/user/main";  
  70.     }  
  71.       
  72.       
  73.     @RequestMapping("/manage")  
  74.     public String manage(ModelMap modelMap){  
  75.         LOGGER.info("显示主页面");  
  76.         modelMap.addAttribute("msg""manage");  
  77.         return "/user/option";  
  78.     }  
  79.       
  80.     @RequestMapping("/save")  
  81.     public String save(ModelMap modelMap){  
  82.         LOGGER.info("保存");  
  83.         modelMap.addAttribute("msg""save");  
  84.         return "/user/option";  
  85.     }  
  86.       
  87.     @RequestMapping("/update")  
  88.     public String update(ModelMap modelMap){  
  89.         LOGGER.info("修改");  
  90.         modelMap.addAttribute("msg""update");  
  91.         return "/user/option";  
  92.     }  
  93.       
  94.     @RequestMapping("/delete")  
  95.     public String delete(ModelMap modelMap){  
  96.         LOGGER.info("删除");  
  97.         modelMap.addAttribute("msg""delete");  
  98.         return "/user/option";  
  99.     }  
  100.       
  101. }  
  102. </span>  

 9、前台

login.jsp


[html]  view plain copy
  1. <span style="font-size:14px;"><%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>  
  2. <%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>  
  3. <%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>  
  4. <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>  
  5. <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>  
  6.   
  7. <%  
  8.     String path = request.getContextPath();  
  9.     String basePath = request.getScheme() + "://"  
  10.             + request.getServerName() + ":" + request.getServerPort()  
  11.             + path + "/";  
  12. %>  
  13. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
  14. <html>  
  15. <head>  
  16. <base href="<%=basePath%>" />  
  17. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
  18. <title>login</title>  
  19. </head>  
  20. <body>  
  21.     <div>${sessionScope.SPRING_SECURITY_LAST_EXCEPTION.message}</div>  
  22.   
  23.     <form:form action="j_spring_security_check" modelAttribute="acctUser" method="post">  
  24.         <form:errors path="*" cssStyle="color:red;" />  
  25.         <br />  
  26.         用户:<form:input path="nickName" />  
  27.         <br />  
  28.         密码:<form:password path="nickPassword" />  
  29.         <br />  
  30.         <form:button>登录</form:button>  
  31.     </form:form>  
  32. </body>  
  33. </html></span>  

main.jsp
[html]  view plain copy
  1. <span style="font-size:14px;"><%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>  
  2. <%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>  
  3. <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>  
  4. <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>  
  5. <%@taglib prefix="security" uri="http://www.springframework.org/security/tags"%>  
  6.   
  7. <%  
  8.     String path = request.getContextPath();  
  9.     String basePath = request.getScheme() + "://"  
  10.             + request.getServerName() + ":" + request.getServerPort()  
  11.             + path + "/";  
  12. %>  
  13. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
  14. <html>  
  15. <head>  
  16. <base href="<%=basePath%>" />  
  17. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
  18. <title>login</title>  
  19. </head>  
  20. <body>  
  21.   
  22.     welcome! <security:authentication property="name"/>  
  23.     <br/>  
  24.           后台获取用户名:${username }  
  25.     <div style="border: 1px; "><a target="_blank" href="j_spring_security_logout">注销</a></div>  
  26.       
  27.     <br/>  
  28.       
  29.     <security:authorize ifAnyGranted="ROLE_浏览用户">  
  30.     <div>  
  31.         <a target="_blank" href="user/showInfo.htmls">全部用户</a>  
  32.     </div>  
  33.     </security:authorize>  
  34.       
  35.       
  36.     <security:authorize ifAllGranted="ROLE_管理用户">  
  37.         <div>  
  38.             <a target="_blank" href="user/manage.htmls">管理用户</a>  
  39.         </div>  
  40.     </security:authorize>  
  41.       
  42.     <div>  
  43.         <a target="_blank" href="user/save.htmls">添加用户</a>  
  44.     </div>  
  45.     <div>  
  46.         <a target="_blank" href="user/update.htmls">修改部用户</a>  
  47.     </div>  
  48.     <div>  
  49.         <a target="_blank" href="user/delete.htmls">删除用户</a>  
  50.     </div>  
  51.       
  52. </body>  
  53. </html></span>  

10、测试

    现在andy用户拥有“浏览用户”和“添加用户”权限

用户密码错误时:

     Maven搭建Spring Security3.2项目详解_第2张图片

  正确密码登陆后:

      

     Maven搭建Spring Security3.2项目详解_第3张图片

点击添加用户,正确跳转。如下:


Maven搭建Spring Security3.2项目详解_第4张图片


点击全部用户,无权限提示。

Maven搭建Spring Security3.2项目详解_第5张图片

11、Spring security自定义认证错误提示

    首先,拷贝spring-security-core写的messages_zh_CN.properties国际化文件,放到项目的src/main/resources目录中

          修改对应的提示,按照我们自己的需求,我命名为messages.properties

   其次, 我们需在spring的配置文件中添加如下内容:

[html]  view plain copy
  1. <span style="font-size:14px;"><span style="font-size:14px;">    <!-- 定义上下文返回的消息的国际化 -->  
  2.     <bean id="messageSource"  
  3.         class="org.springframework.context.support.ReloadableResourceBundleMessageSource">  
  4.         <property name="basename" value="classpath:messages" />  
  5.     </bean>  
  6.   
  7.     <bean id="localeResolver"  
  8.         class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver" /></span></span>  

ok,Maven搭建Spring+Hibernate+security整合完毕。

你可能感兴趣的:(SpringMVC框架)