Spring学习记录(Spring Securit)

从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 {
	
	@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>





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值