`
萧_瑟
  • 浏览: 157105 次
社区版块
存档分类
最新评论

springMVC security Demo

    博客分类:
  • java
阅读更多

springMVC 结合权限控制。

 

 

项目目录结构(Maven形式)


 

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.royal</groupId>
  <artifactId>springMVCSecurityDemo</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>springMVCSecurityDemo</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    
	<!-- mysql驱动 -->
    <dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<version>5.1.20</version>
	</dependency>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-jdbc</artifactId>
		<version>3.1.0.RELEASE</version>
	</dependency>

	<!-- Spring 3 -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-core</artifactId>
		<version>3.1.0.RELEASE</version>
	</dependency>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-web</artifactId>
		<version>3.1.0.RELEASE</version>
	</dependency>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-webmvc</artifactId>
		<version>3.1.0.RELEASE</version>
	</dependency>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-context</artifactId>
		<version>3.1.0.RELEASE</version>
	</dependency>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-beans</artifactId>
		<version>3.1.0.RELEASE</version>
	</dependency>
	
	<!-- Spring Security -->
	<dependency>
		<groupId>org.springframework.security</groupId>
		<artifactId>spring-security-core</artifactId>
		<version>3.0.7.RELEASE</version>
		<exclusions>  
	        <exclusion>  
	            <groupId>org.aspectj</groupId>  
	            <artifactId>aspectjrt</artifactId>  
	        </exclusion> 
    	</exclusions>
	</dependency>
	<dependency>
		<groupId>org.springframework.security</groupId>
		<artifactId>spring-security-web</artifactId>
		<version>3.0.7.RELEASE</version>
	</dependency>
	<dependency>
		<groupId>org.springframework.security</groupId>
		<artifactId>spring-security-config</artifactId>
		<version>3.0.7.RELEASE</version>
	</dependency>
	
	<!-- 标签库 -->
	<dependency>
		<groupId>org.springframework.security</groupId>
		<artifactId>spring-security-taglibs</artifactId>
		<version>3.0.7.RELEASE</version>
	</dependency>
	
  </dependencies>
</project>

 

 

载入后的jar包


 

web.xml

 

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
	xmlns="http://java.sun.com/xml/ns/javaee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
	
	<display-name>SpringMVCSecurityDemo Application</display-name>
	
	<listener>
	    <listener-class>
	        org.springframework.web.context.ContextLoaderListener
	    </listener-class>
	</listener>
	
	<context-param>
	    <param-name>contextConfigLocation</param-name>
	    <param-value>
	        /WEB-INF/applicationContext-dataAccess.xml
	        /WEB-INF/spring-security.xml
	    </param-value>
	</context-param>
	
	<!-- spring mvc -->
	<servlet>  
        <servlet-name>mvc-dispatcher</servlet-name>  
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
        <load-on-startup>1</load-on-startup>  
        <init-param>  
            <param-name>contextConfigLocation</param-name>  
            <param-value>/WEB-INF/spring-mvc.xml</param-value>  
        </init-param>  
    </servlet>  
      
    <servlet-mapping>  
        <servlet-name>mvc-dispatcher</servlet-name>  
        <url-pattern>/</url-pattern>  
    </servlet-mapping>  
	
	<!-- 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>
	
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  
</web-app>
 

 

其中applicationContext-dataAccess.xml是进行访问mysql数据库的dataSource配置,等会儿再说。

 

先看其他的配置文件。

 

 

spring-mvc.xml

 

<beans xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.springframework.org/schema/beans"
    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" >
        
    <context:component-scan base-package="com.royal.controller"/>
    
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
        <property name="prefix" value="/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    
</beans>
 

 

两点:1.扫描Cotroller       2. 访问目标文件时自动于其添加前缀/pages/和后缀.jsp

 

 

 

OK,看下控制类。

 

LoginController.java

 

package com.royal.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * 登录控制类
 * @author Royal
 *
 */
@Controller
public class LoginController {
	
	@RequestMapping(value = "/login" , method = RequestMethod.GET)
	public String gotoLogin(ModelMap model){
		return "login";
	}
	
	/**
	 * 访问地址:http://ip:port/project/welcome
	 * @param model
	 * @return
	 */
	@RequestMapping(value = "/user" , method = RequestMethod.GET)
	public String gotoUser(ModelMap model){
		model.addAttribute("message", "USER");
		//寻找页面user.jsp,地址变为:http://ip:port/project/user.jsp
		return "user";
	}
	
	@RequestMapping(value = "/admin" , method = RequestMethod.GET)
	public String gotoAdmin(ModelMap model){
		model.addAttribute("message", "ADMIN");
		//寻找页面admin.jsp,地址变为:http://ip:port/project/admin.jsp
		return "admin";
	}

}

 

 

至此,springMVC配置完成。

 

接下来结合进权限控制。

 

 

spring-security.xml

 

<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.3.xsd">
        
    <http auto-config="true">
        <!-- 拥有ROLE_ADMIN的角色权限才可以访问 -->
        <intercept-url pattern="/admin" access="ROLE_ADMIN" />
        <!-- 拥有ROLE_USER的角色权限才可以访问 -->
        <intercept-url pattern="/user" access="ROLE_USER"/>
        <!-- 用户注销时,跳转到登录界面 -->
        <logout logout-success-url="/login"/>
        <!-- 记住我,两周之内不必登陆 -->
        <remember-me key="_spring_security_remember_me"/>
        <!-- 防御会话伪造攻击 -->
        <session-management session-fixation-protection="none"/>
        <!-- 取消默认的spring自带的spring_security_login页面,自定义登录界面. 默认访问user页面 -->
        <intercept-url pattern="/login" access="IS_AUTHENTICATED_ANONYMOUSLY" />
        <form-login login-page="/login"
                authentication-failure-url="/login?error=true"
                default-target-url="/user" /> 
    </http>
    
    <authentication-manager>
	     <authentication-provider>
	         <!-- 硬编码形式 -->
<!-- 	         <user-service> -->
<!-- 	             以admin的形式登录,你就有ROLE_USER,ROLE_ADMIN两个用户角色的权限进行访问 -->
<!-- 	             <user name="admin" password="admin" authorities="ROLE_USER,ROLE_ADMIN" /> -->
<!-- 	               以user的形式登录,你只有ROLE_USER的用户角色的权限进行访问 -->
<!-- 	             <user name="user" password="user" authorities="ROLE_USER"/> -->
<!-- 	         </user-service> -->

	         <jdbc-user-service 
	                 data-source-ref="dataSource" 
	                 users-by-username-query="select username,password,enabled from tb_user where username = ? and enabled = 1"
	                 authorities-by-username-query="select u.username,r.name from tb_user u join tb_user_role ur on u.id = ur.user_id join tb_role r on r.id = ur.role_id where u.username = ?" />
	         
	     </authentication-provider>
     </authentication-manager>
     
</beans:beans>
 

 

以上有2种形式的权限声明,显然第一种硬编码形式的我们是不可能用到实际项目中的;所以采用第二种结合数据库的形式

 

 

OK,这样的话,那就看下数据库的结构。

 

mysql数据库结构


存在三张表

 

1. tb_role  权限表    id为主键


2.tb_user  用户表    id为主键


 

3.中间表,权限表和用户表间的桥梁     user_id 和 role_id 同时为主键,且user_id为tb_user表id的外键、role_id为tb_role表id的外键。


 

OK,表的关系已经构建完成,以上描述的关系形式是:royal作为“游客”,只有ROLE_USER标识的权限;admin作为“管理员”,同时拥有ROLE_USER和ROLE_ADMIN标识的权限。

 

 

好,回到配置文件中。

 

注意到这段代码了吗? 注意SQL语句的写法,要查询的表别写错了。

 

<jdbc-user-service 
	                 data-source-ref="dataSource" 
	                 users-by-username-query="select username,password,enabled from tb_user where username = ? and enabled = 1"
	                 authorities-by-username-query="select u.username,r.name from tb_user u join tb_user_role ur on u.id = ur.user_id join tb_role r on r.id = ur.role_id where u.username = ?" />

 

 

现在大概能猜到它的意思了吧?对,它就是相当于硬编码时配置的用户名和密码形式。

 

 <!-- 硬编码形式 -->
	         <user-service>
	             以admin的形式登录,你就有ROLE_USER,ROLE_ADMIN两个用户角色的权限进行访问
	             <user name="admin" password="admin" authorities="ROLE_USER,ROLE_ADMIN" />
	               以user的形式登录,你只有ROLE_USER的用户角色的权限进行访问
	             <user name="user" password="user" authorities="ROLE_USER"/>
	         </user-service>
 

 

 

好了,现在再看下连接mysql数据库的配置。

 

applicationContext-dataAccess.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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context-2.5.xsd">
	
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">  
    	<property name="driverClassName" value="com.mysql.jdbc.Driver" />  
        <property name="url" value="jdbc:mysql://localhost:3306/db_springsecurity" />  
        <property name="username" value="root" />  
        <property name="password" value="123" />  
    </bean>
    
</beans>

 

 

 简单点就好了,对应好自己的数据库名,连接名和密码。

 

配置呢,就差不多这样了,最后给几个页面测试,其中一个页面需要声明一下,那就是登录页面,我没有采用默认的,我重写了,所以你在上面的spring-security.xml中可以看到下面这段代码的说明。

 

<!-- 取消默认的spring自带的spring_security_login页面,自定义登录界面. 默认访问user页面 -->
        <intercept-url pattern="/login" access="IS_AUTHENTICATED_ANONYMOUSLY" />
        <form-login login-page="/login"
                authentication-failure-url="/login?error=true"
                default-target-url="/user" /> 
 

 

login.jsp---登录页面

 

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ page isELIgnored="false"%>
<%
	String path = request.getContextPath();
	String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">

<title>springMVCSecurityDemo</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">

<style type="text/css">
div.error {
	width: 260px;
	border: 2px solid red;
	background-color: yellow;
	text-align: center;
}

div.hide {
	display: none;
}
</style>

</head>

<body onload='document.f.j_username.focus();'>
	<!-- 注意这个form的每个参数 -->
	<form name="f" action="<%=path%>/j_spring_security_check" method='POST'>
		<fieldset>
			<legend>登录</legend>
			用户:<input type="text" name="j_username"
				value="${sessionScope['SPRING_SECURITY_LAST_USERNAME']}" /><br />
			密码:<input type="password" name="j_password" /><br /> <input
				type="checkbox" name="_spring_security_remember_me" />两周之内不必登陆<br />
			<input type="submit" value="登录" /> <input type="reset" value="重置" />
		</fieldset>
	</form>
	
	<!-- 如果登录失败 -->
	<div class="error ${param.error == true ? '' : 'hide'}">
		登陆失败<br>
		${sessionScope['SPRING_SECURITY_LAST_EXCEPTION'].message}
	</div>
</body>
</html>
 

 

user.jsp---游客页面

 

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ page isELIgnored="false"%>
<%@ taglib prefix="sec"
	uri="http://www.springframework.org/security/tags"%>
<%
	String path = request.getContextPath();
	String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">

<title>springMVCSecurityDemo</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
	<link rel="stylesheet" type="text/css" href="styles.css">
	-->
</head>

<body>
	<h1>Message:${message}</h1>
	<sec:authorize ifAllGranted="ROLE_ADMIN,ROLE_USER">  
  		admin and user  
	</sec:authorize> 
	<br/> 
	<sec:authorize ifAnyGranted="ROLE_ADMIN,ROLE_USER">  
  		admin or user  
	</sec:authorize> 
	<br/> 
	<sec:authorize ifNotGranted="ROLE_ADMIN">  
  		not admin  
	</sec:authorize> 
	<br/> 
	<a href="j_spring_security_logout">注销</a>
</body>
</html>

<!-- ifAllGranted,只有当前用户同时拥有ROLE_ADMIN和ROLE_USER两个权限时,才能显示标签内部内容。   -->
<!-- ifAnyGranted,如果当前用户拥有ROLE_ADMIN或ROLE_USER其中一个权限时,就能显示标签内部内容。   -->
<!-- ifNotGranted,如果当前用户没有ROLE_ADMIN时,才能显示标签内部内容。 -->
 

 

看到了吗?我们不但在访问路径上做了权限的控制,同时在页面中也做了相应的权限控制。

 

 

admin.jsp---管理员页面

 

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ page isELIgnored="false" %> 
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>springMVCSecurityDemo</title>
	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">    
	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
	<meta http-equiv="description" content="This is my page">
	<!--
	<link rel="stylesheet" type="text/css" href="styles.css">
	-->
  </head>
  
  <body>
    <h1>Message:${message}</h1>
    <a href="j_spring_security_logout">logout</a>
  </body>
</html>

 

 

 

文件都准备完成了,跑tomcat服务器之前先勾选好启动时需要的jar包。



OK,启动好服务器之后可以开始测试了。

 

 

Now,开始....

 

 

http://localhost:8080/springMVCSecurityDemo/         这当然就是index.jsp页面了。



 http://localhost:8080/springMVCSecurityDemo/user   当键入这个地址的时候,便会开始spring security的控制了,地址会变为 http://localhost:8080/springMVCSecurityDemo/login



 输入错误的用户名或密码



输入正确后(当然你访问的是 http://localhost:8080/springMVCSecurityDemo/user,所以你的输入和数据库相对应的royal,royal.如果输入了admin,admin的话,那么它就进入默认的成功路径了,也就是下面这段代码声明的。)

 

<form-login login-page="/login"
                authentication-failure-url="/login?error=true"
                default-target-url="/user" /> 

 默认的路径: default-target-url="/user" ,所以它进入的还是user.jsp 

 



 此时你便是ROLE_ADMIN管理员权限,所以你也可以进入admin.jsp的页面



 OK,我们logout,注销出来用ROLE_USER身份登录试试。

 

http://localhost:8080/springMVCSecurityDemo/user



 现在你键入访问地址访问admin.jsp

http://localhost:8080/springMVCSecurityDemo/admin



 你会发现forbidden了,为什么?因为你现在不是ROLE_ADMIN身份了呗。

 

当然,还有“两周之内不必登录”remeber me的功能就自己去测试完了,没问题。

 

也好,就这样吧。

 

  • 大小: 18.9 KB
  • 大小: 21.3 KB
  • 大小: 9.2 KB
  • 大小: 16.2 KB
  • 大小: 16.8 KB
  • 大小: 15 KB
  • 大小: 57.5 KB
  • 大小: 97.7 KB
  • 大小: 15.3 KB
  • 大小: 28.3 KB
  • 大小: 31.8 KB
  • 大小: 28.2 KB
  • 大小: 26.4 KB
  • 大小: 27.7 KB
  • 大小: 33.5 KB
分享到:
评论
2 楼 xly1981 2013-07-16  

DROP TABLE IF EXISTS `tb_role`;
CREATE TABLE `tb_role` (
  `Id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `remark` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

LOCK TABLES `tb_role` WRITE;
/*!40000 ALTER TABLE `tb_role` DISABLE KEYS */;
INSERT INTO `tb_role` VALUES (1,'ROLE_ADMIN','管理员');
INSERT INTO `tb_role` VALUES (2,'ROLE_USER','游客');
/*!40000 ALTER TABLE `tb_role` ENABLE KEYS */;
UNLOCK TABLES;



DROP TABLE IF EXISTS `tb_user`;
CREATE TABLE `tb_user` (
  `Id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  `enabled` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


LOCK TABLES `tb_user` WRITE;
/*!40000 ALTER TABLE `tb_user` DISABLE KEYS */;
INSERT INTO `tb_user` VALUES (1,'admin','admin','1');
INSERT INTO `tb_user` VALUES (2,'royal','royal','1');
/*!40000 ALTER TABLE `tb_user` ENABLE KEYS */;
UNLOCK TABLES;



DROP TABLE IF EXISTS `tb_user_role`;
CREATE TABLE `tb_user_role` (
  `Id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  `role_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;



LOCK TABLES `tb_user_role` WRITE;

INSERT INTO `tb_user_role` VALUES (1,1,1);
INSERT INTO `tb_user_role` VALUES (2,2,2);
INSERT INTO `tb_user_role` VALUES (3,3,3);
1 楼 ocaicai 2012-12-07  
非常的简洁、深刻,希望有更多精彩的文章!

相关推荐

Global site tag (gtag.js) - Google Analytics