Maven搭建Spring Security3.2项目详解

前言

本来是打算在上一篇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三个包,如下

               <!-- 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>

2、配置security的配置文件

我们新建一个配置文件(起名随意),我这儿就叫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>

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

2.1、静态文件管理

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

2.2、session对话管理

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>

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容器配置

<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监听。

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

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>

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

5、Security的认证错误提示

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

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

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

6.1、后台获取

<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>

6.1、前台获取

先引入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>

7、前台标签授权

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

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

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

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

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

8、后台Controller

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>

UserController类

<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>

9、前台

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>

main.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="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>

10、测试

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

用户密码错误时:

正确密码登陆后:

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

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

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

首先,拷贝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>

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

后续

遗留问题,通用的重写security提示信息,其他的都能国际化汉语提示,但是

唯独

ConcurrentSessionControlStrategy.exceededAllowed=\u5DF2\u7ECF\u6709 {0} \u4E2A\u7528\u6237\u767B\u5F55\uFF0C\u4E0D\u80FD\u91CD\u590D\u767B\u5F55

我修改重复登录提示时,还是security原来自带的提示,如下:

希望又遇到的共同留言探讨。

博客地址:

源码地址:

时间: 2024-08-10 17:54:49

Maven搭建Spring Security3.2项目详解的相关文章

Maven搭建Spring+Struts2+Hibernate项目详解

前言 这篇主要采用Maven搭建Spring+Struts2+Hibernate的整合项目,复习一下SSH框架,虽然spring提供自己的MVC框架,但是Spring也提供和其他框架的无缝整合,采用组件形式对个框架进行管理,项目实例是按照真实企业里面的开发搭建,也是web的最后一片了.数据库使用mysql,连接池使用的是Druid数据源(这些都无关紧要,可以随时的替换),下面就将详细的介绍一下Maven搭建Spring,Struts2,和hibernation的步奏. 1.数据库设计 数据库库表

利用Intellij+MAVEN搭建SpringJDBC+MySql+SpringMVC项目详解

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion&

IDEA中maven搭建Spring+SpringMVC+mybatis项目

一.介绍 使用IDEA搭建maven web项目,整合框架Spring+SpringMVC+mybatis 项目结构图: 二.搭建 1.新建maven项目 2.创建项目结构(如上图) 3.配置pom.xml 1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 2 xsi:schemaLocation=

Myeclipse下使用Maven搭建spring boot2.0项目

现在需要搭建spring boot框架,并实现一个HelloWorld的项目,让程序真正运行起来. 一.在pom.xml中引入spring-boot-start-parent,spring官方的叫stater poms,它可以提供dependency management,也就是依赖管理,引入以后在声明其它dependency的时候就不需要version了. <parent> <groupId>org.springframework.boot</groupId> <

Maven 搭建spring boot多模块项目

Maven 搭建spring boot多模块项目 备注:所有项目都在idea中创建 1.idea创建maven项目 1-1: 删除src,target目录,只保留pom.xml 1-2: 根目录pom.xml可被子模块继承,因此项目只是demo,未考虑太多性能问题,所以将诸多依赖 都写在根级`pom.xml`,子模块只需继承就可以使用. 1-3: 根级pom.xml文件在附录1 1-4: 依赖模块 mybatis spring-boot相关模块 2.创建子模块(module) 2-1: file

maven搭建spring项目pom有关配置说明

<dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-context-support</artifactId>            <version>${spring.version}</version>        </dependency> maven搭建spring项目p

eclipse里面构建maven项目详解(转载)

本文来源于:http://my.oschina.net/u/1540325/blog/548530 eclipse里面构建maven项目详解 1       环境安装及分配 Maven是基于项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的软件项目管理工具.Maven主要服务于基于java平台的项目构建.依赖管理和项目信息管理,无论是小型的开源类库项目,还是大型的企业级应用,maven都能大显身手. 置于maven的安装过程及在eclipse里面配置maven,请看我在

Spring中AOP实例详解

Spring中AOP实例详解 需要增强的服务 假如有以下service,他的功能很简单,打印输入的参数并返回参数. @Service public class SimpleService { public String getName(String name) { System.out.println(get name is: + name); return name; } } 定义切面和切点 @Component @Aspect public class L ogAspect { // 定义切

Spring Data操作Redis详解

Spring Data操作Redis详解 Redis是一种NOSQL数据库,Key-Value形式对数据进行存储,其中数据可以以内存形式存在,也可以持久化到文件系统.Spring data对Redis进行了很好的封装,用起来也是十分的得心应手.Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库.缓存和消息中间件. 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted se