您的位置:首页 > 编程语言 > Java开发

Spring学习记录(Spring Securit)

2014-12-02 22:02 141 查看
从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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: