Spring学习记录(Spring Securit)
2014-12-02 22:02
141 查看
从URL访问级别、方法调用级别、页面视图显示级别和领域对象级别上用Spring Security加强Web应用安全。
一、加强URL访问安全
假定开发一个网上留言板应用,用户可以查看留言、记录留言、删除留言以及查询某一条留言,通过这个应用来理解SS的基本操作。
接下来建一个服务接口,包含留言板的操作:
创建对应实现类:
web.xml配置文件设置:
Spring配置文件相关设置,此处分离成三个不同的文件:board-service.xml、board-servlet.xml、boardsecurity.xml,配置如下(需用到springmvc相关知识):
board-servlet.xml:
board-service.xml:
创建控制器和页面视图:
此外,用户可以再留言板上张贴留言,因此需要创建对应的表单控制器:
最后用户还可以单击留言表中的删除按钮删除张贴的留言,创建如下控制器:
如果工程名为Board,可以在Web容器(如Tomcat)中打开列表页面:http://localhost:8080/Board/messageList.htm
请求流程步骤:1、DispatcherServlet拦截所有的URL请求;2、DispatcherServlet询问BeanNameUrlHandlerMapping,根据messageList找到对应的Controller;3、DispatcherServlet分发给MessageListController来处理这个请求;4、MessageListController返回一个逻辑视图名"messageList";5、DispatcherServlet询问它的视图解析器(InternalResourceViewResolver)查找名为messageList的视图,InternalResourceViewResolver返回/WEB-INF/jsp/messageList.jsp路径;6、DispatcherServlet将请求导向对应页面
加入security,在web.xml中增加过滤器:
boardsecurity.xml:
此时,我们可以直接访问messageList.htm,因为它开放给匿名用户,而如果直接访问messagePost.htm,则会被重新定向到Spring Security生成的默认登录页面。
二、登录到Wen应用
现在我们取消spring自动配置的http服务属性auto-config="true",手动配置登录页,匿名用户,remember me等
首先创建登录页login.jsp:
修改boardsecurity.xml配置文件:
在messageList.jsp中增加按钮测试:
一、加强URL访问安全
假定开发一个网上留言板应用,用户可以查看留言、记录留言、删除留言以及查询某一条留言,通过这个应用来理解SS的基本操作。
package com.zk.ss.pojo; /** * 留言板类 * */ public class Message { private long id; private String author; //留言人姓名 private String title; //留言标题 private String body; //留言内容
接下来建一个服务接口,包含留言板的操作:
public interface MessageBoardService { List<Message> listMessage(); //展示留言列表 void postMessage(Message message);//张贴留言 void deleteMessage(Message message);//删除留言 Message findMessageById(Long messageId);//查询留言 }
创建对应实现类:
public class MessageBoardServiceImpl implements MessageBoardService { //以张贴时间为键的留言列表集合 private Map<Long, Message> messages = new LinkedHashMap<Long, Message>(); public List<Message> listMessage() { return new ArrayList<Message>(messages.values()); } //上传留言需线程安全 public synchronized void postMessage(Message message) { message.setId(System.currentTimeMillis()); messages.put(message.getId(), message); } //删除留言需线程安全 public synchronized void deleteMessage(Message message) { messages.remove(message.getId()); } public Message findMessageById(Long messageId) { return messages.get(messageId); } }
web.xml配置文件设置:
<!-- 不采用默认配置applicationContext.xml需要指定路径文件 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/board-service.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>board</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>board</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
Spring配置文件相关设置,此处分离成三个不同的文件:board-service.xml、board-servlet.xml、boardsecurity.xml,配置如下(需用到springmvc相关知识):
board-servlet.xml:
<context:component-scan base-package="com.zk.ss" /> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp"></property> <property name="suffix" value=".jsp"></property> </bean>
board-service.xml:
<bean id="messageBoardService" class="com.zk.ss.service.MessageBoardServiceImpl"></bean>
创建控制器和页面视图:
@Controller @RequestMapping(value="/messageList*") public class MessageListController { @Autowired private MessageBoardService messageBoardService; @RequestMapping(method = RequestMethod.GET) public String generateList(Model model){ //生成一个不可变的list集合 List<Message> messages = java.util.Collections.emptyList(); messages = messageBoardService.listMessage(); model.addAttribute("messages", messages); return "messageList"; } }
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE> <html> <head> <title>Message List</title> </head> <body> <c:forEach items="${messages }" var="message"> <table> <tr><td>Author</td><td>${message.author }</td></tr> <tr><td>Title</td><td>${message.title }</td></tr> <tr><td>Body</td><td>${message.body }</td></tr> <tr><td colspan="2"><a href="messageDelete?messageId=${message.id }">Delete</a></td></tr> </table> <hr/> </c:forEach> <a href="messagePost.htm">Post</a> </body> </html>
此外,用户可以再留言板上张贴留言,因此需要创建对应的表单控制器:
@Controller @RequestMapping("/messagePost") public class MessagePostController { @Autowired private MessageBoardService messageBoardService; @RequestMapping(method = RequestMethod.GET) public String setupForm(Model model){ Message message = new Message(); model.addAttribute("message", message); return "messagePost"; } @RequestMapping(method = RequestMethod.POST) public String onSubmit(@ModelAttribute("message")Message message,BindingResult result){ if(result.hasErrors()){ return "messagePost"; }else{ messageBoardService.postMessage(message); return "redirect:messageList"; } } }
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <!DOCTYPE> <html> <head> <title>Message Post</title> </head> <body> <form:form method="POST" modelAttribute="message"> <table> <tr><td>Title</td><td><form:input path="title" /></td></tr> <tr><td>Body</td><td><form:textarea path="body" /></td></tr> <tr><td colspan="2"><input type="submit"" value="POST" /></td></tr> </table> </form:form> </body> </html>
最后用户还可以单击留言表中的删除按钮删除张贴的留言,创建如下控制器:
@Controller @RequestMapping(value="/messageDelete*") public class MessageDeleteController { @Autowired private MessageBoardService messageBoardService; @RequestMapping(method = RequestMethod.GET) public String messageDelete(@RequestParam(required=true,value="messageId")Long messageId,Model model){ Message message = messageBoardService.findMessageById(messageId); messageBoardService.deleteMessage(message); model.addAttribute("messages", messageBoardService.listMessage()); return "redirect:messageList"; } }
如果工程名为Board,可以在Web容器(如Tomcat)中打开列表页面:http://localhost:8080/Board/messageList.htm
请求流程步骤:1、DispatcherServlet拦截所有的URL请求;2、DispatcherServlet询问BeanNameUrlHandlerMapping,根据messageList找到对应的Controller;3、DispatcherServlet分发给MessageListController来处理这个请求;4、MessageListController返回一个逻辑视图名"messageList";5、DispatcherServlet询问它的视图解析器(InternalResourceViewResolver)查找名为messageList的视图,InternalResourceViewResolver返回/WEB-INF/jsp/messageList.jsp路径;6、DispatcherServlet将请求导向对应页面
加入security,在web.xml中增加过滤器:
<context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/board-service.xml /WEB-INF/board-service.xml </param-value> </context-param> <!-- 配置DelegatingFilterProxy实例,将HTTP请求过滤委派给Spring Security中定义的过滤器 --> <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>
boardsecurity.xml:
<?xml version='1.0' encoding='UTF-8'?> <beans:beans xmlns='http://www.springframework.org/schema/security' xmlns:beans='http://www.springframework.org/schema/beans' 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-3.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd '> <!-- 对特定的url进行拦截,规定访问需要的权限 --> <http auto-config="true"> <intercept-url pattern="/messageList*" access="ROLE_USER,ROLE_ANONYMOUS"/> <intercept-url pattern="/messagePost*" access="ROLE_USER"/> <intercept-url pattern="/messageDelete*" access="ROLE_ADMIN"/> </http> <!-- 配置验证服务,Security支持多种验证方法,包括数据库或LDAP存储库的验证 对于简单的安全需求,还可以直接在<user-service>中定义 --> <authentication-manager> <authentication-provider> <user-service> <user name="admin" password="admin" authorities="ROLE_ADMIN,ROLE_USER"/> <user name="user1" password="1234" authorities="ROLE_USER"/> </user-service> </authentication-provider> </authentication-manager> </beans:beans>
此时,我们可以直接访问messageList.htm,因为它开放给匿名用户,而如果直接访问messagePost.htm,则会被重新定向到Spring Security生成的默认登录页面。
二、登录到Wen应用
现在我们取消spring自动配置的http服务属性auto-config="true",手动配置登录页,匿名用户,remember me等
首先创建登录页login.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE> <html> <head> <title>Login</title> <!-- 基于表单的登录 需在xml文档中配置(我们取消了auto-config="true"的http自动配置服务) <http> ... <form-login /> </http> 该登录页可代替spring security默认的登录页spring_security_login 配置在web-inf根目录下,可让用户直接访问 --> </head> <!-- 此处的表单操作url和字段名称都是固定的 --> <body> <c:if test="${not empty param.error}"> <font color="red"> Login error.<br> Reason:${sessionScope["SPRING_SECURITY_LAST_EXCEPTION"].message } </font> </c:if> <form method="POST" action="<c:url value="/j_spring_security_check" />" > <table> <tr><td align="right"">Username</td><td><input type="text" name="j_username" /></td></tr> <tr><td align="right">Password</td><td><input type="password" name="j_password" /></td></tr> <tr><td align="right">Remember me</td><td><input type="checkbox" name="_spring_security_remember_me" /></td></tr> <tr><td colspan="2" align="right"><input type="submit" value="Login" /><input type="reset" value="Reset" ></td></tr> </table> </form> </body> </html>
修改boardsecurity.xml配置文件:
<!-- 对特定的url进行拦截,规定访问需要的权限 --> <http><!-- 删除auto-config="true" 禁用http自动配置 --> <intercept-url pattern="/messageList*" access="ROLE_USER,ROLE_GUEST"/> <intercept-url pattern="/messagePost*" access="ROLE_USER"/> <intercept-url pattern="/messageDelete*" access="ROLE_ADMIN"/> <!-- 配置自定义的表单登录页面 1、如果用户请求安全url时显示登录界面,登录成功后会被重新定位到目标url, 但是用户直接访问登录界面,登录成功后会重新定向到上下文跟路径(http://localhost:8080/board/),默认的欢迎页面 default-target-url可以设置用户直接访问登陆界面登录成功后显示的页面 2、在默认的登录页面下,登录失败后spring会带着错误的信息显示在这个登录页面,如果自定义登录页面就必须配置 authentication-failure-url,指定错误时重定向的url,例如:可以使用error请求参数再次重定向到自定义的登录页面 --> <form-login login-page="/login.jsp" default-target-url="/messageList" authentication-failure-url="/login.jsp?error=true" /> <!-- 注销服务: 默认情况下,注销服务映射到url /j_spring_security_logout --> <logout logout-success-url="/login.jsp"/> <!-- 匿名登录: 用户可以自定义匿名用户的用户名和权限 --> <anonymous username="guest" granted-authority="ROLE_GUEST" /> <!-- remember me支持 --> <remember-me/> </http>
在messageList.jsp中增加按钮测试:
<body> <c:forEach items="${messages }" var="message"> <table> <tr><td>Author</td><td>${message.author }</td></tr> <tr><td>Title</td><td>${message.title }</td></tr> <tr><td>Body</td><td>${message.body }</td></tr> <tr><td colspan="2"><a href="messageDelete?messageId=${message.id }">Delete</a></td></tr> </table> <hr/> </c:forEach> <a href="messagePost.html">Post</a> <a href="<c:url value="/login.jsp" />">Login</a> <a href="<c:url value="/j_spring_security_logout" />">Logout</a> </body>
相关文章推荐
- jqGrid分页技术学习(五)spring jdbc 通用DAO——修改一条记录
- spring.net 学习笔记之 AOP (异常记录实例)转
- Spring学习记录一(SpringIOC容器初级)
- 记录我的Spring学习过程,大神勿看
- Spring学习记录(一)
- jqGrid分页技术学习(三)spring jdbc 通用DAO——添加一条记录
- Spring学习记录(2) Spring MVC+Mybatis 注解配置
- Spring 学习记录 5
- Spring 学习记录 4 扫描包
- spring学习笔记(点滴记录)
- spring security3学习记录
- maven学习记录2.2:spring-mvc.xml配置
- maven学习记录2.3:spring-mybatis.xml配置
- Spring 学习记录 6
- Spring 学习记录 冷兵器时代的故事
- jqGrid分页技术学习(六)spring jdbc 通用DAO——查询所有记录
- 记录Spring.net学习中遇到的各种问题
- Spring mvc ,spring ,ibatis 学习记录(2)
- spring AOP学习记录1
- spring-data-jpa 多条件查询 学习记录