本来是打算在上一篇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三个包,如下
org.springframework.security
spring-security-core
${security.version}
org.springframework.security
spring-security-config
${security.version}
org.springframework.security
spring-security-taglibs
${security.version}
我们新建一个配置文件(起名随意),我这儿就叫spring-security.xml,我现在定义了几个权限,权限信息表内容如下:
其中:管理用户和全部用户的权限将通过jsp中security标签配置,其他的通过spring-security.xml文件配置。
先贴出spring-security.xml的文件,详细配置含义我将做一个简单的说明:
spring-security配置
我们对于css,image,js这些不用权限拦截。
session管理max-sessions="1"配置了最多有一个用户登录,(在wab.xml还要添加如下:)
org.springframework.security.web.session.HttpSessionEventPublisher
值为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:配置密码加密规则。
contextConfigLocation
classpath:spring.xml
classpath:spring-hibernate.xml
classpath:spring-security.xml
springSecurityFilterChain
org.springframework.web.filter.DelegatingFilterProxy
springSecurityFilterChain
/*
org.springframework.security.web.session.HttpSessionEventPublisher
配置了加载的spring-security文件,security拦截的filter,以及security的session监听。
UserDetailsServiceImpl如下:
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
*
* 描述: 实现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 authorities = getAuthorities(acctUser);
// 将没有使用到的属性设置为true
UserDetails userDetails = new User(acctUser.getNickName(),
acctUser.getNickPassword(), true, true, true, true, authorities);
return userDetails;
}
// 获得用户所有角色的权限
private Set getAuthorities(AcctUser acctUser) {
Set authoritySet = new HashSet();
// 默认所有的用户有"浏览用户"的权利
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;
}
}
我们可以通过sessionScope.SPRING_SECURITY_LAST_EXCEPTION.message获取认证错误。
6、Security获取session中的用户名和用户信息
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();
}
先引入security的标签库:
<%@taglib prefix="security" uri="http://www.springframework.org/security/tags"%>
通过security:authorize标签设置权限,其有三种属性分别如下:
ifAnyGranted::只有当前用户拥有所指定的权限中的一个的时候,就能显示标签内部的内容(相当于“或”的关系)
ifAllGranted:只有当前用户拥有所指定的权限时,才显示标签的内容(相当于“与”的关系)
ifNotGranted: 没有指定的权限的时候,显示标签内容(相当于“非”的关系)
自然也可以通过method限制是那种http的请求(http的请求有8种:- GET - DELETE - HEAD - OPTIONS - POST - PUT - PATCH - TRACE)。
LoginController
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";
}
}
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 showUserInfos(){
LOGGER.info("查询用户全部用户");
List 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";
}
}
login.jsp
<%@ 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 + "/";
%>
login
${sessionScope.SPRING_SECURITY_LAST_EXCEPTION.message}
用户:
密码:
登录
<%@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 + "/";
%>
login
welcome!
后台获取用户名:${username }
现在andy用户拥有“浏览用户”和“添加用户”权限
用户密码错误时:
正确密码登陆后:
点击添加用户,正确跳转。如下:
点击全部用户,无权限提示。
首先,拷贝spring-security-core写的messages_zh_CN.properties国际化文件,放到项目的src/main/resources目录中
修改对应的提示,按照我们自己的需求,我命名为messages.properties
其次, 我们需在spring的配置文件中添加如下内容:
遗留问题,通用的重写security提示信息,其他的都能国际化汉语提示,但是
唯独
ConcurrentSessionControlStrategy.exceededAllowed=\u5DF2\u7ECF\u6709 {0} \u4E2A\u7528\u6237\u767B\u5F55\uFF0C\u4E0D\u80FD\u91CD\u590D\u767B\u5F55
我修改重复登录提示时,还是security原来自带的提示,如下:
希望又遇到的共同留言探讨。
博客地址:http://blog.csdn.net/fengshizty
源码地址:http://download.csdn.net/detail/fengshizty/8444061