标签:spring security 国际化 security3.2 权限控制
本来是打算在上一篇SpringMVC+Hibernate上写的,结果发现上面那篇一起整合的,结果发现上一篇内容实在是太长了,就另起一篇,这篇主要是采用 Maven搭建Spring+SpringMVC+Hibernate+Security整合,而Spring+SpringMVC+Hibernate已经在上一篇介绍了,在这篇将不再重复写了,主要说明一下SpringSecurity3.2权限控制整合搭建,以及配置,使用注意事项等。
SpringSecurity的Api文档地址:查看
在pom.xml中引入我们需要引入spring-security-core,spring-security-config,spring-security-taglibs三个包,如下
<!-- spring-security --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> <version>${security.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>${security.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> <version>${security.version}</version> </dependency>
我们新建一个配置文件(起名随意),我这儿就叫spring-security.xml,我现在定义了几个权限,权限信息表内容如下:
其中:管理用户和全部用户的权限将通过jsp中security标签配置,其他的通过spring-security.xml文件配置。
先贴出spring-security.xml的文件,详细配置含义我将做一个简单的说明:
<span style="font-size:14px;"><?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:security="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd" default-lazy-init="true"> <description>spring-security配置</description> <!-- 静态资源 --> <security:http pattern="/css/**" security="none" /> <security:http pattern="/js/**" security="none" /> <security:http pattern="/images/**" security="none" /> <security:http> <security:intercept-url pattern="/user/save*" access="ROLE_添加用户" requires-channel="any" /> <security:intercept-url pattern="/user/delete*" access="ROLE_删除用户" requires-channel="any" /> <security:intercept-url pattern="/user/user*" access="ROLE_浏览用户" requires-channel="any" /> <security:intercept-url pattern="/user/update*" access="ROLE_修改用户" requires-channel="any" /> <security:session-management> <security:concurrency-control expired-url="/login/login.htmls?repeat=true" max-sessions="1" error-if-maximum-exceeded="true" /> </security:session-management> <security:form-login login-page="/login/login.htmls" authentication-failure-url="/login/login.htmls?error=true" default-target-url="/user/main.htmls" always-use-default-target='true' username-parameter="nickName" password-parameter="nickPassword" /> <security:logout invalidate-session="true" logout-success-url="/login/login.htmls?logout=true" /> </security:http> <!-- 认证配置 自定义认证实现UserDetailsService接口 --> <security:authentication-manager> <security:authentication-provider user-service-ref="userDetailsService"> <!-- 配置密码加密方式 --> <security:password-encoder hash="md5" /> </security:authentication-provider> </security:authentication-manager> <bean id="userDetailsService" class="org.andy.work.service.impl.UserDetailsServiceImpl" /> </beans></span>
我们对于css,image,js这些不用权限拦截。
session管理max-sessions="1"配置了最多有一个用户登录,(在wab.xml还要添加如下:)
<span style="font-size:14px;"><!-- spring-security 管理session配置 --> <listener> <listener-class> org.springframework.security.web.session.HttpSessionEventPublisher</listener-class> </listener></span>
值为false时,若果有一个用户已经登录,下一个用户登录将踢掉上一个用户。
自然在session-manager中我们可以配置session失效时,跳转的url如,invalid-session-url="/invalidSession.jsp",如果session失效时,刷新将跳转到invalidSession.jsp页面。
通过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。
通过security:logout标签配置注销,invalidate-session:注销时session是否失效。logout-success-url:注销成功后跳转的地址。
logout-url:为注销的url,如果不填写,则默认为j_spring_security_logout
security:intercept-url为要拦截权限认证的的url,pattern为拦截的正则匹配url,access:所需的权限,可以是一个权限组,用逗号隔开,requires-channel:拦截http还是https的,如果两个都拦截用any。
通过我们数据库的权限表信息,我们自定义权限认证机制,需要我们实现UserDetailsService接口,配置用户密码的加密方式。
security:password-encoder:配置密码加密规则。
<span style="font-size:14px;"> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:spring.xml classpath:spring-hibernate.xml classpath:spring-security.xml </param-value> </context-param> <!-- Spring-Security filter 最好配置在控制层filter的前面 --> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- spring-security 管理session配置 --> <listener> <listener-class> org.springframework.security.web.session.HttpSessionEventPublisher</listener-class> </listener></span>
配置了加载的spring-security文件,security拦截的filter,以及security的session监听。
UserDetailsServiceImpl如下:
<span style="font-size:14px;">package org.andy.work.service.impl; import java.util.HashSet; import java.util.Set; import org.andy.work.dao.UserDao; import org.andy.work.entity.AcctAuthority; import org.andy.work.entity.AcctRole; import org.andy.work.entity.AcctUser; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; /** * 创建时间:2015-2-9 下午5:24:44 * * @author andy * @version 2.2 * <p> * 描述: 实现SpringSecurity的UserDetails接口 自定义认证 */ public class UserDetailsServiceImpl implements UserDetailsService { private static final Logger LOGGER = Logger .getLogger(UserDetailsServiceImpl.class); // 注入查询User的dao层 @Autowired private UserDao userDao; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { LOGGER.info("认证用户:" + username); // 查询数据库获取改用户的信息 AcctUser acctUser = userDao.findByNickName(username); if (null == acctUser) { throw new UsernameNotFoundException("用户:" + username + "不存在"); } Set<GrantedAuthority> authorities = getAuthorities(acctUser); // 将没有使用到的属性设置为true UserDetails userDetails = new User(acctUser.getNickName(), acctUser.getNickPassword(), true, true, true, true, authorities); return userDetails; } // 获得用户所有角色的权限 private Set<GrantedAuthority> getAuthorities(AcctUser acctUser) { Set<GrantedAuthority> authoritySet = new HashSet<GrantedAuthority>(); // 默认所有的用户有"浏览用户"的权利 authoritySet.add(new SimpleGrantedAuthority("ROLE_浏览用户")); // 依次添加 if (null != acctUser.getAcctRoles() && acctUser.getAcctRoles().size() > 0) for (AcctRole role : acctUser.getAcctRoles()) { if (null != role.getAcctAuthorities() && role.getAcctAuthorities().size() > 0) for (AcctAuthority authority : role.getAcctAuthorities()) { authoritySet.add(new SimpleGrantedAuthority(authority .getPrefixedName())); } } return authoritySet; } } </span>
我们可以通过sessionScope.SPRING_SECURITY_LAST_EXCEPTION.message获取认证错误。
6、Security获取session中的用户名和用户信息
security将用户信息存放在session中,可以通过以下两种获得:
<span style="font-size:14px;"> //获取security的上下文 SecurityContext securityContext = SecurityContextHolder.getContext(); //获取认证对象 Authentication authentication = securityContext.getAuthentication(); //在认证对象中获取主体对象 Object principal = authentication.getPrincipal(); String username = ""; if(principal instanceof UserDetails){ username = ((UserDetails) principal).getUsername(); }else { username = principal.toString(); }</span>
先引入security的标签库:
<span style="font-size:14px;"><%@taglib prefix="security" uri="http://www.springframework.org/security/tags"%></span>
<span style="font-size:14px;"><security:authentication property="name"/></span>
通过security:authorize标签设置权限,其有三种属性分别如下:
ifAnyGranted::只有当前用户拥有所指定的权限中的一个的时候,就能显示标签内部的内容(相当于“或”的关系)
ifAllGranted:只有当前用户拥有所指定的权限时,才显示标签的内容(相当于“与”的关系)
ifNotGranted: 没有指定的权限的时候,显示标签内容(相当于“非”的关系)
自然也可以通过method限制是那种http的请求(http的请求有8种:- GET - DELETE - HEAD - OPTIONS - POST - PUT - PATCH - TRACE)。
LoginController
<span style="font-size:14px;"><span style="font-size:14px;">package org.andy.work.controller; import org.andy.work.entity.AcctUser; import org.apache.log4j.Logger; import org.springframework.stereotype.Controller; import org.springframework.validation.Errors; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; /** * 创建时间:2015-2-10 下午9:23:34 * * @author andy * @version 2.2 描述: */ @Controller @RequestMapping("/login") public class LoginController { private static final Logger LOGGER = Logger .getLogger(LoginController.class); @RequestMapping("/login") public String login(@ModelAttribute AcctUser acctUser, @RequestParam(required = false) Boolean logout, Errors errors ) { LOGGER.info("login"); if(null != logout){ errors.reject("msg", "已经安全退出"); } return "/login/login"; } }</span> </span>
<span style="font-size:14px;">package org.andy.work.controller; import java.util.List; import org.andy.work.entity.AcctUser; import org.andy.work.service.UserService; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; /** * 创建时间:2015-2-7 上午11:49:00 * @author andy * @version 2.2 * 描述: 用户Controller */ @Controller @RequestMapping("/user") public class UserController { private static final Logger LOGGER = Logger.getLogger(UserController.class); @Autowired private UserService userService; @RequestMapping("/showInfo/{userId}") public String showUserInfo(ModelMap modelMap, @PathVariable String userId){ LOGGER.info("查询用户:" + userId); AcctUser userInfo = userService.load(userId); modelMap.addAttribute("userInfo", userInfo); return "/user/showInfo"; } @RequestMapping("/showInfos") public @ResponseBody List<AcctUser> showUserInfos(){ LOGGER.info("查询用户全部用户"); List<AcctUser> userInfos = userService.findAll(); return userInfos; } @RequestMapping("/main") public String main(ModelMap modelMap){ LOGGER.info("显示主页面"); //后台获取security保存的session中的用户信息 //获取security的上下文 SecurityContext securityContext = SecurityContextHolder.getContext(); //获取认证对象 Authentication authentication = securityContext.getAuthentication(); //在认证对象中获取主体对象 Object principal = authentication.getPrincipal(); String username = ""; if(principal instanceof UserDetails){ username = ((UserDetails) principal).getUsername(); }else { username = principal.toString(); } modelMap.addAttribute("username", username); return "/user/main"; } @RequestMapping("/manage") public String manage(ModelMap modelMap){ LOGGER.info("显示主页面"); modelMap.addAttribute("msg", "manage"); return "/user/option"; } @RequestMapping("/save") public String save(ModelMap modelMap){ LOGGER.info("保存"); modelMap.addAttribute("msg", "save"); return "/user/option"; } @RequestMapping("/update") public String update(ModelMap modelMap){ LOGGER.info("修改"); modelMap.addAttribute("msg", "update"); return "/user/option"; } @RequestMapping("/delete") public String delete(ModelMap modelMap){ LOGGER.info("删除"); modelMap.addAttribute("msg", "delete"); return "/user/option"; } } </span>
login.jsp
<span style="font-size:14px;"><%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <%@taglib prefix="spring" uri="http://www.springframework.org/tags"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <base href="<%=basePath%>" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>login</title> </head> <body> <div>${sessionScope.SPRING_SECURITY_LAST_EXCEPTION.message}</div> <form:form action="j_spring_security_check" modelAttribute="acctUser" method="post"> <form:errors path="*" cssStyle="color:red;" /> <br /> 用户:<form:input path="nickName" /> <br /> 密码:<form:password path="nickPassword" /> <br /> <form:button>登录</form:button> </form:form> </body> </html></span>
<span style="font-size:14px;"><%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <%@taglib prefix="security" uri="http://www.springframework.org/security/tags"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <base href="<%=basePath%>" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>login</title> </head> <body> welcome! <security:authentication property="name"/> <br/> 后台获取用户名:${username } <div style="border: 1px; "><a target="_blank" href="j_spring_security_logout">注销</a></div> <br/> <security:authorize ifAnyGranted="ROLE_浏览用户"> <div> <a target="_blank" href="user/showInfo.htmls">全部用户</a> </div> </security:authorize> <security:authorize ifAllGranted="ROLE_管理用户"> <div> <a target="_blank" href="user/manage.htmls">管理用户</a> </div> </security:authorize> <div> <a target="_blank" href="user/save.htmls">添加用户</a> </div> <div> <a target="_blank" href="user/update.htmls">修改部用户</a> </div> <div> <a target="_blank" href="user/delete.htmls">删除用户</a> </div> </body> </html></span>
现在andy用户拥有“浏览用户”和“添加用户”权限
用户密码错误时:
正确密码登陆后:
点击添加用户,正确跳转。如下:
点击全部用户,无权限提示。
首先,拷贝spring-security-core写的messages_zh_CN.properties国际化文件,放到项目的src/main/resources目录中
修改对应的提示,按照我们自己的需求,我命名为messages.properties
其次, 我们需在spring的配置文件中添加如下内容:
<span style="font-size:14px;"><span style="font-size:14px;"> <!-- 定义上下文返回的消息的国际化 --> <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basename" value="classpath:messages" /> </bean> <bean id="localeResolver" class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver" /></span></span>
遗留问题,通用的重写security提示信息,其他的都能国际化汉语提示,但是
唯独
ConcurrentSessionControlStrategy.exceededAllowed=\u5DF2\u7ECF\u6709 {0} \u4E2A\u7528\u6237\u767B\u5F55\uFF0C\u4E0D\u80FD\u91CD\u590D\u767B\u5F55
我修改重复登录提示时,还是security原来自带的提示,如下:
希望又遇到的共同留言探讨。
博客地址:
源码地址:
标签:spring security 国际化 security3.2 权限控制
原文地址:http://blog.csdn.net/fengshizty/article/details/43732815