SpringMVC+security
转自:http://blog.csdn.net/bigshotzhang/article/details/12346979
下面我们将实现关于Spring Security3的一系列教程.
最终的目标是整合Spring Security + Spring3MVC
完成类似于SpringSide3中mini-web的功能.
Spring Security是什么?
关于Spring Security学习的资料.
最重要,最齐全的中文资料当然是family168的中文文档
Spring Security2参考文档
附件包含了一个很好的初入门的PDF教程.
最好是花30分钟先照着PDF上的教程一步一步的操作.
虽然没有实际的应用价值,但对初学者认识SpringSecurity3很有帮助.
我们的项目目录结构最终是:
需要添加的jar包:
我们先实现一个controller:
MainController.java
- package org.liukai.tutorial.controller;
- import org.apache.log4j.Logger;
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- @Controller
- @RequestMapping("/main")
- public class MainController {
- protected static Logger logger = Logger.getLogger("controller");
- /**
- * 跳转到commonpage页面
- *
- * @return
- */
- @RequestMapping(value = "/common", method = RequestMethod.GET)
- public String getCommonPage() {
- logger.debug("Received request to show common page");
- return "commonpage";
- }
- /**
- * 跳转到adminpage页面
- *
- * @return
- */
- @RequestMapping(value = "/admin", method = RequestMethod.GET)
- public String getAadminPage() {
- logger.debug("Received request to show admin page");
- return "adminpage";
- }
- }
该controller有两个mapping映射:
main/admin
现在我们将同过Spring Security3框架实现成功登陆的人都能访问到main/common.
但只有拥有admin权限的用户才能访问main/admin.
我们先在web.xml中开启Spring3MVC和SpringSecurity3.
web.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app id="WebApp_ID" version="2.4"
- xmlns="http://java.sun.com/xml/ns/j2ee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
- http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
- <!-- SpringSecurity必须的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>
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>
- /WEB-INF/spring-security.xml
- /WEB-INF/applicationContext.xml
- </param-value>
- </context-param>
- <servlet>
- <servlet-name>spring</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>spring</servlet-name>
- <url-pattern>/</url-pattern>
- </servlet-mapping>
- <listener>
- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
- </listener>
- </web-app>
要启用SpringSecurity3,我们需要完成以下两步:
1.在web.xml中声明DelegatingFilterProxy.
- <filter-mapping>
- <filter-name>springSecurityFilterChain</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
表示项目中所有路径的资源都要经过SpringSecurity.
2.导入指定的SpringSecurity配置 :spring-security.xml
关于spring-security.xml的配置.
我们把这个放到后面配置.以便更详细的讲解.
注意一点.最好是将DelegatingFilterProxy写在DispatcherServlet之前.否则
SpringSecurity可能不会正常工作.
在web.xml中我们定义servlet:spring.
按照惯例,我们必须声明一个spring-servle.xml
spring-servle.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
- <!-- 定义一个视图解析器 -->
- <bean id="viewResolver"
- class="org.springframework.web.servlet.view.InternalResourceViewResolver"
- p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />
- </beans>
这个XML配置声明一个视图解析器.在控制器中会根据JSP名映射到/ WEB-INF/jsp中相应的位置.
然后创建一个applicationContext.xml.
applicationContext.xml.
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:mvc="http://www.springframework.org/schema/mvc"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd
- http://www.springframework.org/schema/mvc
- http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
- <!-- 激活spring的注解. -->
- <context:annotation-config />
- <!-- 扫描注解组件并且自动的注入spring beans中.
- 例如,他会扫描@Controller 和@Service下的文件.所以确保此base-package设置正确. -->
- <context:component-scan base-package="org.liukai.tutorial" />
- <!-- 配置注解驱动的Spring MVC Controller 的编程模型.注:次标签只在 Servlet MVC工作! -->
- <mvc:annotation-driven />
- </beans>
接着是创建JSP页面
commonpage.jsp
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>Insert title here</title>
- </head>
- <body>
- <h1>Common Page</h1>
- <p>每个人都能访问的页面.</p>
- <a href="/spring3-security-integration/main/admin"> Go AdminPage </a>
- <br />
- <a href="/spring3-security-integration/auth/login">退出登录</a>
- </body>
- </html>
adminpage.jsp
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>Insert title here</title>
- </head>
- <body>
- <h1>Admin Page</h1>
- <p>管理员页面</p>
- <a href="/spring3-security-integration/auth/login">退出登录</a>
- </body>
- </html>
这两个JSP对应着
当然还有登陆页面和拒绝访问页面
loginpage.jsp
- <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
- <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
- <%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>Insert title here</title>
- </head>
- <body>
- <h1>Login</h1>
- <div id="login-error">${error}</div>
- <form action="../j_spring_security_check" method="post">
- <p>
- <label for="j_username">Username</label> <input id="j_username"
- name="j_username" type="text" />
- </p>
- <p>
- <label for="j_password">Password</label> <input id="j_password"
- name="j_password" type="password" />
- </p>
- <input type="submit" value="Login" />
- </form>
- </body>
- </html>
deniedpage.jsp
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>Insert title here</title>
- </head>
- <body>
- <h1>你的权限不够!</h1>
- <p>只有拥有Admin权限才能访问!</p>
- <a href="/spring3-security-integration/auth/login">退出登录</a>
- </body>
- </html>
还有一个controller用于映射上面两个JSP页面..
LoginLogoutController.java
- package org.liukai.tutorial.controller;
- import org.apache.log4j.Logger;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.ModelMap;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- import org.springframework.web.bind.annotation.RequestParam;
- @Controller
- @RequestMapping("auth")
- public class LoginLogoutController {
- protected static Logger logger = Logger.getLogger("controller");
- /**
- * 指向登录页面
- */
- @RequestMapping(value = "/login", method = RequestMethod.GET)
- public String getLoginPage(
- @RequestParam(value = "error", required = false) boolean error,
- ModelMap model) {
- logger.debug("Received request to show login page");
- if (error == true) {
- // Assign an error message
- model.put("error",
- "You have entered an invalid username or password!");
- } else {
- model.put("error", "");
- }
- return "loginpage";
- }
- /**
- * 指定无访问额权限页面
- *
- * @return
- */
- @RequestMapping(value = "/denied", method = RequestMethod.GET)
- public String getDeniedPage() {
- logger.debug("Received request to show denied page");
- return "deniedpage";
- }
- }
该controller实现了两个映射
auth/denied --显示拒绝访问页面
最后,让我们看看spring-security.xml的配置
spring-security.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:security="http://www.springframework.org/schema/security"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/security
- http://www.springframework.org/schema/security/spring-security-3.0.xsd">
- <!-- Spring-Security 的配置 -->
- <!-- 注意开启use-expressions.表示开启表达式.
- see:http://www.family168.com/tutorial/springsecurity3/html/el-access.html
- -->
- <security:http auto-config="true" use-expressions="true" access-denied-page="/auth/denied" >
- <security:intercept-url pattern="/auth/login" access="permitAll"/>
- <security:intercept-url pattern="/main/admin" access="hasRole('ROLE_ADMIN')"/>
- <security:intercept-url pattern="/main/common" access="hasRole('ROLE_USER')"/>
- <security:form-login
- login-page="/auth/login"
- authentication-failure-url="/auth/login?error=true"
- default-target-url="/main/common"/>
- <security:logout
- invalidate-session="true"
- logout-success-url="/auth/login"
- logout-url="/auth/logout"/>
- </security:http>
- <!-- 指定一个自定义的authentication-manager :customUserDetailsService -->
- <security:authentication-manager>
- <security:authentication-provider user-service-ref="customUserDetailsService">
- <security:password-encoder ref="passwordEncoder"/>
- </security:authentication-provider>
- </security:authentication-manager>
- <!-- 对密码进行MD5编码 -->
- <bean class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" id="passwordEncoder"/>
- <!--
- 通过 customUserDetailsService,Spring会自动的用户的访问级别.
- 也可以理解成:以后我们和数据库操作就是通过customUserDetailsService来进行关联.
- -->
- <bean id="customUserDetailsService" class="org.liukai.tutorial.service.CustomUserDetailsService"/>
- </beans>
在配置中我们可以看到三个URL对应的三个权限
- <security:intercept-url pattern="/auth/login" access="permitAll"/>
- <security:intercept-url pattern="/main/admin" access="hasRole('ROLE_ADMIN')"/>
- <security:intercept-url pattern="/main/common" access="hasRole('ROLE_USER')"/>
需要注意的是我们使用了SpringEL表达式来指定角色的访问.
以下是表达式对应的用法.
hasRole([role]) 返回 true 如果当前主体拥有特定角色。
hasAnyRole([role1,role2]) 返回 true 如果当前主体拥有任何一个提供的角色 (使用逗号分隔的字符串队列)
principal 允许直接访问主体对象,表示当前用户
authentication 允许直接访问当前 Authentication对象 从SecurityContext中获得
permitAll 一直返回true
denyAll 一直返回false
isAnonymous() 如果用户是一个匿名登录的用户 就会返回 true
isRememberMe() 如果用户是通过remember-me 登录的用户 就会返回 true
isAuthenticated() 如果用户不是匿名用户就会返回true
isFullyAuthenticated() 如果用户不是通过匿名也不是通过remember-me登录的用户时, 就会返回true。
所以
- <security:intercept-url pattern="/auth/login" access="permitAll"/>
表示所有的人都可以访问/auth/login.
- <security:intercept-url pattern="/main/admin" access="hasRole('ROLE_ADMIN')"/>
- <security:intercept-url pattern="/main/common" access="hasRole('ROLE_USER')"/>
则表示只有拥有对应的角色才能访问.
- <security:form-login
- login-page="/auth/login"
- authentication-failure-url="/auth/login?error=true"
- default-target-url="/main/common"/>
表示通过 /auth/login这个映射进行登录.
如果验证失败则返回一个URL:/auth/login?error=true
如果登录成功则默认指向:/main/common
- security:logout
- invalidate-session="true"
- logout-success-url="/auth/login"
- logout-url="/auth/logout"/>
很简单.我们开启了session失效功能.
注销URL为:/auth/logout
注销成功后转向:/auth/login
- <!-- 指定一个自定义的authentication-manager :customUserDetailsService -->
- <security:authentication-manager>
- <security:authentication-provider user-service-ref="customUserDetailsService">
- <security:password-encoder ref="passwordEncoder"/>
- </security:authentication-provider>
- </security:authentication-manager>
- <!-- 对密码进行MD5编码 -->
- <bean class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" id="passwordEncoder"/>
- <!--
- 通过 customUserDetailsService,Spring会自动的用户的访问级别.
- 也可以理解成:以后我们和数据库操作就是通过customUserDetailsService来进行关联.
- -->
- <bean id="customUserDetailsService" class="org.liukai.tutorial.service.CustomUserDetailsService"/>
一个自定义的CustomUserDetailsService,是实现SpringSecurity的UserDetailsService接口,但我们重写了他即便于我们进行数据库操作.
DbUser.java
- package org.liukai.tutorial.domain;
- public class DbUser {
- private String username;
- private String password;
- private Integer access;
- //getter/setter
- }
通过一个初始化的List来模拟数据库操作.
UserDao.java
- package org.liukai.tutorial.dao;
- import java.util.ArrayList;
- import java.util.List;
- import org.apache.log4j.Logger;
- import org.liukai.tutorial.domain.DbUser;
- public class UserDao {
- protected static Logger logger = Logger.getLogger("dao");
- public DbUser getDatabase(String username) {
- List<DbUser> users = internalDatabase();
- for (DbUser dbUser : users) {
- if (dbUser.getUsername().equals(username) == true) {
- logger.debug("User found");
- return dbUser;
- }
- }
- logger.error("User does not exist!");
- throw new RuntimeException("User does not exist!");
- }
- /**
- * 初始化数据
- */
- private List<DbUser> internalDatabase() {
- List<DbUser> users = new ArrayList<DbUser>();
- DbUser user = null;
- user = new DbUser();
- user.setUsername("admin");
- // "admin"经过MD5加密后
- user.setPassword("21232f297a57a5a743894a0e4a801fc3");
- );
- users.add(user);
- user = new DbUser();
- user.setUsername("user");
- // "user"经过MD5加密后
- user.setPassword("ee11cbb19052e40b07aac0ca060c23ee");
- );
- users.add(user);
- return users;
- }
- }
自定义UserDetailsService .可以通过继承UserDetailsService
来达到灵活的自定义UserDetailsService
关于UserDetailsService更多信息. 可以查看SpringSecurity3文档
CustomUserDetailsService.java
- package org.liukai.tutorial.service;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.List;
- import org.apache.log4j.Logger;
- import org.liukai.tutorial.dao.UserDao;
- import org.liukai.tutorial.domain.DbUser;
- import org.springframework.dao.DataAccessException;
- import org.springframework.security.core.GrantedAuthority;
- import org.springframework.security.core.authority.GrantedAuthorityImpl;
- 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;
- /**
- * 一个自定义的service用来和数据库进行操作. 即以后我们要通过数据库保存权限.则需要我们继承UserDetailsService
- *
- * @author liukai
- *
- */
- public class CustomUserDetailsService implements UserDetailsService {
- protected static Logger logger = Logger.getLogger("service");
- private UserDao userDAO = new UserDao();
- public UserDetails loadUserByUsername(String username)
- throws UsernameNotFoundException, DataAccessException {
- UserDetails user = null;
- try {
- // 搜索数据库以匹配用户登录名.
- // 我们可以通过dao使用JDBC来访问数据库
- DbUser dbUser = userDAO.getDatabase(username);
- // Populate the Spring User object with details from the dbUser
- // Here we just pass the username, password, and access level
- // getAuthorities() will translate the access level to the correct
- // role type
- user = new User(dbUser.getUsername(), dbUser.getPassword()
- .toLowerCase(), true, true, true, true,
- getAuthorities(dbUser.getAccess()));
- } catch (Exception e) {
- logger.error("Error in retrieving user");
- throw new UsernameNotFoundException("Error in retrieving user");
- }
- return user;
- }
- /**
- * 获得访问角色权限
- *
- * @param access
- * @return
- */
- public Collection<GrantedAuthority> getAuthorities(Integer access) {
- );
- // 所有的用户默认拥有ROLE_USER权限
- logger.debug("Grant ROLE_USER to this user");
- authList.add(new GrantedAuthorityImpl("ROLE_USER"));
- // 如果参数access为1.则拥有ROLE_ADMIN权限
- ) == 0) {
- logger.debug("Grant ROLE_ADMIN to this user");
- authList.add(new GrantedAuthorityImpl("ROLE_ADMIN"));
- }
- return authList;
- }
- }
最后启动服务器输入:
http://localhost:8080/spring3-security-integration/auth/login
maven插件启动.
- SpringSecurity3.0.pdf (1.1 MB)
- 下载次数: 819
- spring3-security-integration.zip (25 KB)
- 下载次数: 626
SpringMVC+security的更多相关文章
- springmvc+spring-security+mybatis +redis +solar框架抽取
参考文章:Spring MVC 3 深入总结: 第二章 Spring MVC入门 —— 跟开涛学SpringMVC 参考博客:http://www.cnblogs.com/liukemng/categ ...
- SpringMVC+spring-security+sitemesh+hibernate+freemarker整合-转
http://www.oschina.net/code/snippet_170632_46774 代码分享 当前位置: 代码分享 » Java » Web编程 搜 索 SpringMVC+spr ...
- Spring MVC4 + Spring Security4 + Hibernate实例
http://www.yiibai.com/spring-security/spring-mvc-4-and-spring-security-4-integration-example.html 在这 ...
- SpringMVC 3.1集成Spring Security 3.1
这篇算是一个入门文章,昨天看见有网友提问,spring mvc集成spring security 的时候出错,揣测了一下问题木有解决.我就帮忙给搭建了一个集成框架他说可以,他告诉我这样的文章网上少.今 ...
- SpringMVC 3.2集成Spring Security 3.2集成mybaties
目录结构如下
- SpringMVC 3.2集成Spring Security 3.2
参考:http://www.cnblogs.com/Beyond-bit/p/springmvc_and_springsecurity.html SpringMVC 3.2集成Spring Secur ...
- springmvc maven搭建二之springmvc的security
上一篇文档初步搭建了一个springmvc的web工程,现在要来实现第二步咯.将登录校验整合到项目中,我用的是spring 3.0.2的版本,所以这里的登录用了security来处理.不多说,上代码. ...
- Spring Security教程之整合SpringMVC(六)
一.前言 Spring Security系列教程中,前五篇为同一人所写,而本文是博主依据第三方文章整合而出,与前五篇文章的作者不是同一系列. 但本文以前五篇文章为基础,在前面文章所建立的Spring ...
- SpringSecurity操作指南-在SpringMVC项目上配置Spring Security
随机推荐
- Java经典算法之插入排序(Insert Sort)
插入排序在局部有序的情况下比冒泡排序快一倍,比选择排序快一点. 那什么是插入排序,就是将局部有序的数据向右移动,将未排序的数据插到他的前面 下面我们来解析代码: 这里外层循环out变量从1开始向右移动 ...
- NetCore Netty 框架 BT.Netty.RPC 系列随讲 二 WHO AM I 之 NETTY/NETTY 与 网络通讯 IO 模型之关系?
一:NETTY 是什么? Netty 是什么? 这个问题其实百度上一搜一堆. 这是官方话的描述:Netty 是一个基于NIO的客户.服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个 ...
- printf的实型
参 数 说 明 %f 按实数格式输出,整数部分按实际位数输出,6位小数 %m.nf 总位数m(含小数点),其中有n位小数 %-m.nf 同上,左对齐 %0.xf 输出小数点后x位 %f 后面如 ...
- 8.Layers Editor
图层编辑 Ventuz5中有两种类型的场景,分别是2D图层和3D图层.3D图层包含Content和Hierarchy,而2D图层只包含Content.默认情况下,图层编辑器显示在Ventuz中的左上角 ...
- CSS布局——三栏布局
说到三栏布局,很多都会提到圣杯布局和双飞翼布局这两个经典的三栏布局方式.于是,我在网上搜了一些相关资料,阅读并跟着代码敲了一遍,发现在处理三栏布局上,他们采用的都是两边栏固定,中间栏自适应的策略.在处 ...
- eclipse整合maven下载jar包速度慢问题解决
引用:http://blog.csdn.net/u010154380/article/details/70339538 开发过程中在pom.xml中添加pom的时候,默认是需要从中央仓库中下载,但是下 ...
- 联想 K10(K10e70) 免解锁BL 免rec Magisk Xposed 救砖 ROOT 版本号 S206
>>>重点介绍<<< 第一:本刷机包可卡刷可线刷,刷机包比较大的原因是采用同时兼容卡刷和线刷的格式,所以比较大第二:[卡刷方法]卡刷不要解压刷机包,直接传入手机后用 ...
- service里设置websocket心跳并向fragment发送数据
垃圾小白写了自己看的 /** * service 文件 */ public class SocketService extends Service { //自己定义接口用来传参 private sta ...
- 查看/进入mac根目录的方式
1.通过“前往文件夹”快捷键组合 (1)打开finder,点击上部菜单栏“前往”,然后“个人”,直接跳转. (2)快捷键组合:command + shift + G:注意:打开finder后,再快捷键 ...
- CSS——display:flex
Flex是Flexible Box的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性. 设为Flex布局以后,子元素的float.clear和vertical-align属性 ...