Spring学习记录(Spring Securit)

来源:互联网 发布:linux 编辑文本命令 编辑:程序博客网 时间:2024/04/30 01:34

从URL访问级别、方法调用级别、页面视图显示级别和领域对象级别上用Spring Security加强Web应用安全。

一、加强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 {@Autowiredprivate 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 {@Autowiredprivate 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 {@Autowiredprivate 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.xsdhttp://www.springframework.org/schema/securityhttp://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>





0 0
原创粉丝点击