1、技術(shù)目標(biāo)
- 了解并創(chuàng)建Security框架所需數(shù)據(jù)表
- 為項(xiàng)目添加Spring Security框架
- 掌握Security框架配置
- 應(yīng)用Security框架為項(xiàng)目的CRUD操作綁定權(quán)限
注意:本文所用項(xiàng)目為"影片管理",參看
http://hotstrong.iteye.com/blog/1156785
2、權(quán)限管理需求描述
- 為系統(tǒng)中的每個(gè)操作定義權(quán)限,如定義4個(gè)權(quán)限:
1)超級(jí)權(quán)限,可以使用所有操作
2)添加影片權(quán)限
3)修改影片權(quán)限
4)刪除影片權(quán)限 - 為系統(tǒng)設(shè)置管理員帳號(hào)、密碼
- 為系統(tǒng)創(chuàng)建權(quán)限組,每個(gè)權(quán)限組可以配置多個(gè)操作權(quán)限,如創(chuàng)建2個(gè)權(quán)限組:
1)"Administrator"權(quán)限組,具有超級(jí)權(quán)限
2)"影片維護(hù)"權(quán)限組,具有添加影片、修改影片權(quán)限 - 可將管理員加入權(quán)限組,管理員登錄后具備權(quán)限組所對(duì)應(yīng)操作權(quán)限
- 管理員可不屬于某權(quán)限組,可為管理員直接分配權(quán)限
3、使用準(zhǔn)備
3.1)在數(shù)據(jù)庫(kù)中創(chuàng)建6張表
t_admin 管理員帳號(hào)表
t_role權(quán)限表
t_group 權(quán)限組表
t_group_role權(quán)限組對(duì)應(yīng)權(quán)限表
t_group_user管理員所屬權(quán)限組表
t_user_role管理員對(duì)應(yīng)權(quán)限表
建表SQL語(yǔ)句如下:
- SET FOREIGN_KEY_CHECKS=0;
- ------------------------------
- -- 創(chuàng)建管理員帳號(hào)表t_admin
- -- ----------------------------
- CREATE TABLE `t_admin` (
- `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
- `passwd` varchar(12) NOT NULL DEFAULT '' COMMENT '用戶密碼',
- `nickname` varchar(20) NOT NULL DEFAULT '' COMMENT '用戶名字',
- `phoneno` varchar(32) NOT NULL DEFAULT '' COMMENT '電話號(hào)碼',
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
- -- ----------------------------
- -- 添加3個(gè)管理帳號(hào)
- -- ----------------------------
- INSERT INTO `t_admin` VALUES ('1', 'admin', 'admin', '');
- INSERT INTO `t_admin` VALUES ('4', '123456', 'test', '');
- INSERT INTO `t_admin` VALUES ('5', '111111', '111111', '');
- -- ----------------------------
- -- 創(chuàng)建權(quán)限表t_role
- -- ----------------------------
- CREATE TABLE `t_role` (
- `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
- `role` varchar(40) NOT NULL DEFAULT '',
- `descpt` varchar(40) NOT NULL DEFAULT '' COMMENT '角色描述',
- `category` varchar(40) NOT NULL DEFAULT '' COMMENT '分類',
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=60 DEFAULT CHARSET=utf8;
- -- ----------------------------
- -- 加入4個(gè)操作權(quán)限
- -- ----------------------------
- INSERT INTO `t_role` VALUES ('1', 'ROLE_ADMIN', '系統(tǒng)管理員', '系統(tǒng)管理員');
- INSERT INTO `t_role` VALUES ('2', 'ROLE_UPDATE_FILM', '修改', '影片管理');
- INSERT INTO `t_role` VALUES ('3', 'ROLE_DELETE_FILM', '刪除', '影片管理');
- INSERT INTO `t_role` VALUES ('4', 'ROLE_ADD_FILM', '添加', '影片管理');
- -- ----------------------------
- -- 創(chuàng)建權(quán)限組表
- -- ----------------------------
- CREATE TABLE `t_group` (
- `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
- `groupname` varchar(50) NOT NULL DEFAULT '',
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
- -- ----------------------------
- -- 添加2個(gè)權(quán)限組
- -- ----------------------------
- INSERT INTO `t_group` VALUES ('1', 'Administrator');
- INSERT INTO `t_group` VALUES ('2', '影片維護(hù)');
- -- ----------------------------
- -- 創(chuàng)建權(quán)限組對(duì)應(yīng)權(quán)限表t_group_role
- -- ----------------------------
- CREATE TABLE `t_group_role` (
- `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
- `groupid` bigint(20) unsigned NOT NULL,
- `roleid` bigint(20) unsigned NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `groupid2` (`groupid`,`roleid`),
- KEY `roleid` (`roleid`),
- CONSTRAINT `t_group_role_ibfk_1` FOREIGN KEY (`groupid`) REFERENCES `t_group` (`id`),
- CONSTRAINT `t_group_role_ibfk_2` FOREIGN KEY (`roleid`) REFERENCES `t_role` (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=83 DEFAULT CHARSET=utf8;
- -- ----------------------------
- -- 加入權(quán)限組與權(quán)限的對(duì)應(yīng)關(guān)系
- -- ----------------------------
- INSERT INTO `t_group_role` VALUES ('1', '1', '1');
- INSERT INTO `t_group_role` VALUES ('2', '2', '2');
- INSERT INTO `t_group_role` VALUES ('4', '2', '4');
- -- ----------------------------
- -- 創(chuàng)建管理員所屬權(quán)限組表t_group_user
- -- ----------------------------
- CREATE TABLE `t_group_user` (
- `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
- `userid` bigint(20) unsigned NOT NULL,
- `groupid` bigint(20) unsigned NOT NULL,
- PRIMARY KEY (`id`),
- KEY `userid` (`userid`),
- KEY `groupid` (`groupid`),
- CONSTRAINT `t_group_user_ibfk_2` FOREIGN KEY (`groupid`) REFERENCES `t_group` (`id`),
- CONSTRAINT `t_group_user_ibfk_3` FOREIGN KEY (`userid`) REFERENCES `t_admin` (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8;
- -- ----------------------------
- -- 將管理員加入權(quán)限組
- -- ----------------------------
- INSERT INTO `t_group_user` VALUES ('1', '1', '1');
- INSERT INTO `t_group_user` VALUES ('2', '4', '2');
- -- ----------------------------
- -- 創(chuàng)建管理員對(duì)應(yīng)權(quán)限表t_user_role
- -- 設(shè)置該表可跳過(guò)權(quán)限組,為管理員直接分配權(quán)限
- -- ----------------------------
- CREATE TABLE `t_user_role` (
- `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
- `userid` bigint(20) unsigned NOT NULL,
- `roleid` bigint(20) unsigned NOT NULL,
- PRIMARY KEY (`id`),
- KEY `userid` (`userid`),
- KEY `roleid` (`roleid`),
- CONSTRAINT `t_user_role_ibfk_1` FOREIGN KEY (`userid`) REFERENCES `t_admin` (`id`),
- CONSTRAINT `t_user_role_ibfk_2` FOREIGN KEY (`roleid`) REFERENCES `t_role` (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
3.2)在項(xiàng)目中新增如下jar包(security框架所需jar包):
注意:以下jar包本文已提供下載
spring-security-config-3.1.0.RC2.jar
spring-security-core-3.1.0.RC2.jar
spring-security-taglibs-3.1.0.RC2.jar
spring-security-web-3.1.0.RC2.jar
3.3)創(chuàng)建如下包,放置登錄驗(yàn)證過(guò)濾器代碼:
com.xxx.security
3.4)在src下創(chuàng)建Spring配置文件applicationContext-security.xml,內(nèi)容如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <beans:beans xmlns="http://www.springframework.org/schema/security"
- xmlns:b="http://www.springframework.org/schema/beans" 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.1.xsd">
- <!-- 這里進(jìn)行配置 -->
- </beans:beans>
3.5)在web.xml中加入security配置,如下:
- <?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">
- <welcome-file-list>
- <welcome-file>index.jsp</welcome-file>
- </welcome-file-list>
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>/WEB-INF/applicationContext-*.xml,classpath*:applicationContext-*.xml</param-value>
- </context-param>
- <!-- 配置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>
- <filter>
- <filter-name>struts2</filter-name>
- <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>struts2</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <listener>
- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
- </listener>
- </web-app>
4、站點(diǎn)根路徑下創(chuàng)建登錄頁(yè)面login.jsp,代碼如下:
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- <%@ taglib prefix="s" uri="/struts-tags"%>
- <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
- <%
- String path = request.getContextPath();
- String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path;
- %>
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <title>后臺(tái)登錄</title>
- </head>
- <body onload="document.loginForm.j_username.focus();">
- <!-- 登錄表單 -->
- <form name="loginForm" action="<c:url value='/j_spring_security_check'/>" method="post">
- <!-- 登錄失敗后,顯示之前的登錄名 -->
- 用戶名:<input type='text' name='j_username' class="txtinput"
- value='<c:if test="${not empty param.login_error}" >
- <c:out value="${SPRING_SECURITY_LAST_USERNAME}"/></c:if>' />
- <br />
- 密碼:<input type='password' name='j_password' class="txtinput" />
- <br />
- <input type="checkbox" name="_spring_security_remember_me" />
- 保存登錄信息
- <input name="submit" type="submit" value="提交" />
- <input name="reset" type="reset" value="重置" />
- </form>
- <br />
- <!-- 顯示登錄失敗原因 -->
- <c:if test="${not empty param.error}">
- <font color="red"> 登錄失敗<br />
- <br />
- 原因: <c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}" />. </font>
- </c:if>
- </body>
- </html>
5、站點(diǎn)根路徑下創(chuàng)建注銷頁(yè)面loggedout.jsp,代碼如下:
- <%@page session="false" %>
- <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
- <%@ page pageEncoding="UTF-8"%>
- <%
- String path = request.getContextPath();
- String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path;
- %>
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
- <title>登出</title>
- </head>
- <body>
- 你已經(jīng)退出。
- <a href="<c:url value='/login.jsp'/>">點(diǎn)擊這里登錄</a>
- </body>
- </html>
6、站點(diǎn)根路徑下創(chuàng)建HttpSession超時(shí)提示頁(yè)面timeout.jsp,代碼如下:
- <%@page session="false" %>
- <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
- <%@ page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%>
- <%
- String path = request.getContextPath();
- String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path;
- %>
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <title>用戶失效</title>
- </head>
- <body>
- 你的登錄已經(jīng)失效,請(qǐng)重新登錄。
- <br />
- <a href="<c:url value='/login.jsp'/>" >
- 點(diǎn)擊這里登錄</a>
- </body>
- </html>
7、在com.xxx.security包下創(chuàng)建登錄驗(yàn)證過(guò)濾器,該過(guò)濾器可用于在管理員登錄時(shí)進(jìn)行日志記錄等相關(guān)操作,包括兩個(gè)類:
- LoginUsernamePasswordAuthenticationFilter
- LoginSuccessHandler
7.1)LoginUsernamePasswordAuthenticationFilter代碼如下:
- package com.xxx.security;
- import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
- public class LoginUsernamePasswordAuthenticationFilter extends
- UsernamePasswordAuthenticationFilter {
- }
7.2)LoginSuccessHandler代碼如下:
- package com.xxx.security;
- import java.io.IOException;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import org.springframework.security.core.Authentication;
- import org.springframework.security.core.userdetails.UserDetails;
- import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
- /**
- * 處理管理員登錄日志
- *
- */
- public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler{
- @Override
- public void onAuthenticationSuccess(HttpServletRequest request,
- HttpServletResponse response, Authentication authentication) throws IOException,
- ServletException {
- UserDetails userDetails = (UserDetails)authentication.getPrincipal();
- //輸出登錄提示信息
- System.out.println("管理員 " + userDetails.getUsername() + " 登錄");
- super.onAuthenticationSuccess(request, response, authentication);
- }
- }
8、在applicationContext-security.xml中加入權(quán)限管理配置,如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <beans:beans xmlns="http://www.springframework.org/schema/security"
- xmlns:b="http://www.springframework.org/schema/beans" 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.1.xsd">
- <http >
- <!-- 不攔截login.jsp -->
- <intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
- <!--僅攔截到manager下面的內(nèi)容,具備access對(duì)應(yīng)權(quán)限的-->
- <intercept-url pattern="/manager/**" access="ROLE_ADMIN,ROLE_UPDATE_FILM,ROLE_DELETE_FILM,ROLE_ADD_FILM" />
- <!-- 設(shè)置登錄過(guò)濾器 -->
- <custom-filter before="FORM_LOGIN_FILTER" ref="authenticationProcessingFilter" />
- <!-- 登錄表單設(shè)置 -->
- <form-login login-page="/login.jsp"
- default-target-url="/manager/films.jsp"
- authentication-failure-url="/login.jsp?error=true" />
- <!-- 登出操作后跳轉(zhuǎn)到該頁(yè)面 -->
- <logout logout-success-url="/loggedout.jsp"
- delete-cookies="JSESSIONID" />
- <remember-me />
- <!-- SESSION超時(shí)后跳轉(zhuǎn)到該頁(yè)面 -->
- <session-management invalid-session-url="/timeout.jsp">
- </session-management>
- </http>
- <authentication-manager alias="authenticationManager">
- <authentication-provider>
- <!--
- 直接使用SQL語(yǔ)句查詢登錄帳號(hào)對(duì)應(yīng)權(quán)限,
- users-by-username-query:查詢登錄用戶是否存在
- authorities-by-username-query:查詢登錄用戶權(quán)限(登錄用戶可以不屬于任何組,從t_user_role表中獲取權(quán)限)
- group-authorities-by-username-query:查詢登錄用戶所在組的權(quán)限
- -->
- <jdbc-user-service data-source-ref="dataSource"
- group-authorities-by-username-query="SELECT g.id,g.groupname,role.role
- FROM t_group AS g
- LEFT OUTER JOIN t_group_role AS grouprole ON (g.id = grouprole.groupid)
- LEFT OUTER JOIN t_role AS role ON (role.id = grouprole.roleid)
- LEFT OUTER JOIN t_group_user AS groupuser on (g.id = groupuser.groupid)
- LEFT OUTER JOIN t_admin ON (t_admin.id = groupuser.userid)
- WHERE t_admin.nickname = ?"
- users-by-username-query="SELECT t_admin.nickname AS username,t_admin.passwd as password,'true' AS enabled
- FROM t_admin
- WHERE t_admin.nickname = ?"
- authorities-by-username-query="SELECT t_admin.nickname AS username,role.role as authorities
- FROM t_admin
- LEFT OUTER JOIN t_user_role AS userrole ON(t_admin.id = userrole.userid)
- LEFT OUTER JOIN t_role AS role ON (userrole.roleid = role.id)
- WHERE t_admin.nickname = ?" />
- </authentication-provider>
- </authentication-manager>
- <!-- 自定義消息 -->
- <b:bean id="messageSource"
- class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
- <b:property name="basename"
- value="classpath:org/springframework/security/messages" />
- </b:bean>
- <!-- 定制登錄過(guò)濾器 -->
- <beans:bean id="loginSuccessHandler" class="com.xxx.security.LoginSuccessHandler">
- <b:property name="defaultTargetUrl">
- <!-- 登錄成功后轉(zhuǎn)發(fā)到該頁(yè)面 -->
- <b:value>/manager/films.jsp</b:value>
- </b:property>
- </beans:bean>
- <beans:bean id="authenticationProcessingFilter" class="com.xxx.security.LoginUsernamePasswordAuthenticationFilter">
- <beans:property name="authenticationSuccessHandler" ref="loginSuccessHandler"></beans:property>
- <beans:property name="authenticationFailureHandler" ref="authenticationFailureHandler"></beans:property>
- <beans:property name="authenticationManager" ref="authenticationManager"></beans:property>
- </beans:bean>
- <beans:bean id="authenticationFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
- <beans:property name="defaultFailureUrl">
- <!-- 登錄失敗后轉(zhuǎn)發(fā)到該頁(yè)面 -->
- <beans:value>/login.jsp?error=true</beans:value>
- </beans:property>
- </beans:bean>
- </beans:beans>
9、為影片頁(yè)面films.jsp定制操作權(quán)限,定制后,不同的帳號(hào)登錄會(huì)看到不同的操作,
比如,帳號(hào)"admin"屬于權(quán)限組"Administrator",具備權(quán)限"ROLE_ADMIN",登錄后
可以看到所有操作,帳號(hào)"test"屬于權(quán)限組"影片維護(hù)",具備權(quán)限"ROLE_UPDATE_FILM"
和"ROLE_ADD_FILM",登錄后只能看到"添加影片信息"和"修改"操作
films.jsp頁(yè)面權(quán)限分布圖:
films.jsp代碼如下:
- <%@ page language="java" contentType="text/html; charset=utf-8"
- pageEncoding="utf-8" %>
- <%@taglib uri="/struts-tags" prefix="s" %>
- <%@ taglib prefix="security"
- 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>
- <title>信息操作</title>
- </head>
- <body>
- <s:form action="/film/findFilm" method="post">
- <s:submit value=" 獲取所有影片信息 "></s:submit>
- </s:form>
- <!-- 添加影片操作,登錄帳號(hào)具備ROLE_ADMIN權(quán)限或者ROLE_ADD_FILM權(quán)限可以執(zhí)行 -->
- <security:authorize ifAnyGranted="ROLE_ADMIN,ROLE_ADD_FILM">
- <a href="<%=basePath %>manager/insertFilm.jsp">添加影片信息</a><br />
- </security:authorize>
- <s:if test="filmList != null">
- <table border="1" width="40%">
- <tr>
- <th>序號(hào)</th><th>影片名</th><th>操作</th>
- </tr>
- <%-- 遍歷影片信息 --%>
- <s:iterator var="film" value="filmList" status="st">
- <tr>
- <td><s:property value="#st.index+1" /></td>
- <td><s:property value="fname" /></td>
- <td>
- <!-- 修改影片操作,登錄帳號(hào)具備ROLE_ADMIN權(quán)限或者ROLE_UPDATE_FILM權(quán)限可以執(zhí)行 -->
- <security:authorize ifAnyGranted="ROLE_ADMIN,ROLE_UPDATE_FILM">
- <s:url id="detailUrl" value="/film/detailFilm">
- <s:param name="id" value="%{id}"/>
- </s:url>
- <s:a href="%{detailUrl}">[修改]</s:a>
- </security:authorize>
- <!-- 刪除影片操作,登錄帳號(hào)具備ROLE_ADMIN權(quán)限或者ROLE_DELETE_FILM權(quán)限可以執(zhí)行 -->
- <security:authorize ifAnyGranted="ROLE_ADMIN,ROLE_DELETE_FILM">
- <s:url id="deleteUrl" value="/film/deleteFilm">
- <s:param name="id" value="%{id}"/>
- </s:url>
- <s:a href="%{deleteUrl}">[刪除]</s:a>
- </security:authorize>
- </td>
- </tr>
- </s:iterator>
- </table>
- </s:if>
- </body>
- </html>
- Spring_security3.1框架所需jar包.rar (670.9 KB)
- 下載次數(shù): 1026