知識清單
權限管理原理知識
什麼是權限管理
用戶認證
用戶認證概念
用戶認證流程
關鍵對象
用戶授權
用戶授權概念
授權流程
關鍵對象
權限模型
分配權限
權限控制(授權核心)
基於角色的訪問控制
基於資源的訪問控制
RBAC (Resource based access control) 基於資源的訪問控制權限管理解決方案
什麼是粗粒度權限和細粒度權限?
如何實現粗粒度和細粒度的權限管理
基於url攔截的方式實現
使用權限管理框架來實現
基於URL的權限管理
基於url的權限管理流程
搭建環境
數據庫
/*
SQLyog v10.2
MySQL - 5.1.72-community : Database - shiro
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
/*Table structure for table `sys_permission` */
CREATE TABLE `sys_permission` (
`id` bigint(20) NOT NULL COMMENT '主鍵',
`name` varchar(128) NOT NULL COMMENT '資源名稱',
`type` varchar(32) NOT NULL COMMENT '資源類型:menu,button,',
`url` varchar(128) DEFAULT NULL COMMENT '訪問url地址',
`percode` varchar(128) DEFAULT NULL COMMENT '權限代碼字符串',
`parentid` bigint(20) DEFAULT NULL COMMENT '父結點id',
`parentids` varchar(128) DEFAULT NULL COMMENT '父結點id列表串',
`sortstring` varchar(128) DEFAULT NULL COMMENT '排序號',
`available` char(1) DEFAULT NULL COMMENT '是否可用,1:可用,0不可用',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*Table structure for table `sys_role` */
CREATE TABLE `sys_role` (
`id` varchar(36) NOT NULL,
`name` varchar(128) NOT NULL,
`available` char(1) DEFAULT NULL COMMENT '是否可用,1:可用,0不可用',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*Table structure for table `sys_role_permission` */
CREATE TABLE `sys_role_permission` (
`id` varchar(36) NOT NULL,
`sys_role_id` varchar(32) NOT NULL COMMENT '角色id',
`sys_permission_id` varchar(32) NOT NULL COMMENT '權限id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*Table structure for table `sys_user` */
CREATE TABLE `sys_user` (
`id` varchar(36) NOT NULL COMMENT '主鍵',
`usercode` varchar(32) NOT NULL COMMENT '賬號',
`username` varchar(64) NOT NULL COMMENT '姓名',
`password` varchar(32) NOT NULL COMMENT '密碼',
`salt` varchar(64) DEFAULT NULL COMMENT '鹽',
`locked` char(1) DEFAULT NULL COMMENT '賬號是否鎖定,1:鎖定,0未鎖定',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*Table structure for table `sys_user_role` */
CREATE TABLE `sys_user_role` (
`id` varchar(36) NOT NULL,
`sys_user_id` varchar(32) NOT NULL,
`sys_role_id` varchar(32) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
shiro_sql_table_data.sql/*
SQLyog v10.2
MySQL - 5.1.72-community : Database - shiro
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
/*Data for the table `sys_permission` */
insert into `sys_permission`(`id`,`name`,`type`,`url`,`percode`,`parentid`,`parentids`,`sortstring`,`available`) values
(1,'權限','','',NULL,0,'0/','0','1'),(11,'商品管理','menu','/item/queryItem.action',NULL,1,'0/1/','1.','1'),
(12,'商品新增','permission','/item/add.action','item:create',11,'0/1/11/','','1'),
(13,'商品修改','permission','/item/editItem.action','item:update',11,'0/1/11/','','1'),
(14,'商品刪除','permission','','item:delete',11,'0/1/11/','','1'),
(15,'商品查詢','permission','/item/queryItem.action','item:query',11,'0/1/15/',NULL,'1'),
(21,'用戶管理','menu','/user/query.action','user:query',1,'0/1/','2.','1'),
(22,'用戶新增','permission','','user:create',21,'0/1/21/','','1'),
(23,'用戶修改','permission','','user:update',21,'0/1/21/','','1'),
(24,'用戶刪除','permission','','user:delete',21,'0/1/21/','','1');
/*Data for the table `sys_role` */
insert into `sys_role`(`id`,`name`,`available`) values
('ebc8a441-c6f9-11e4-b137-0adc305c3f28','商品管理員','1'),
('ebc9d647-c6f9-11e4-b137-0adc305c3f28','用戶管理員','1');
/*Data for the table `sys_role_permission` */
insert into `sys_role_permission`(`id`,`sys_role_id`,`sys_permission_id`) values
('ebc8a441-c6f9-11e4-b137-0adc305c3f21','ebc8a441-c6f9-11e4-b137-0adc305c','12'),
('ebc8a441-c6f9-11e4-b137-0adc305c3f22','ebc8a441-c6f9-11e4-b137-0adc305c','11'),
('ebc8a441-c6f9-11e4-b137-0adc305c3f24','ebc9d647-c6f9-11e4-b137-0adc305c','21'),
('ebc8a441-c6f9-11e4-b137-0adc305c3f25','ebc8a441-c6f9-11e4-b137-0adc305c','15'),
('ebc9d647-c6f9-11e4-b137-0adc305c3f23','ebc9d647-c6f9-11e4-b137-0adc305c','22'),
('ebc9d647-c6f9-11e4-b137-0adc305c3f26','ebc8a441-c6f9-11e4-b137-0adc305c','13');
/*Data for the table `sys_user` */
insert into `sys_user`(`id`,`usercode`,`username`,`password`,`salt`,`locked`) values
('lisi','lisi','李四','bf07fd8bbc73b6f70b8319f2ebb87483','uiwueylm','0'),
('zhangsan','zhangsan','張三','cb571f7bd7a6f73ab004a70322b963d5','eteokues','0');
/*Data for the table `sys_user_role` */
insert into `sys_user_role`(`id`,`sys_user_id`,`sys_role_id`) values
('ebc8a441-c6f9-11e4-b137-0adc305c3f28','zhangsan','ebc8a441-c6f9-11e4-b137-0adc305c'),
('ebc9d647-c6f9-11e4-b137-0adc305c3f28','lisi','ebc9d647-c6f9-11e4-b137-0adc305c');
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
查看對應權限模型的數據如下:sys_permission 權限表
開發環境
系統工程架構
系統登錄
用戶的身份信息
/**
* 用戶身份信息,存入Session 由於Tomcat正常關閉時會將Session序列化的本地硬盤上,所以實現Serializable接口
* @author liuxun
*
*/
public class ActiveUser implements Serializable {
private String userid; //用戶id(主鍵)
private String usercode; // 用戶賬號
private String username; // 用戶姓名
....
....
}
mapper
mapper接口:根據用戶賬號查詢用戶(sys_user)信息 (使用逆向工程生成權限相關的PO類和mapper接口)service(進行用戶名和密碼校驗)
/**
* 認證授權服務接口
* @author liuxun
*
*/
public interface SysService {
//根據用戶的身份和密碼進行認證,如果認證通過,返回用戶身份信息
public ActiveUser authenticat(String usercode,String password) throws Exception;
//根據用戶賬號查詢用戶信息
public SysUser findSysUserByUserCode(String userCode) throws Exception;
......
}
方法實現:public class SysServiceImpl implements SysService {
@Autowired
private SysUserMapper sysUserMapper;
public ActiveUser authenticat(String usercode, String password) throws Exception {
/**
* 認證過程: 根據用戶身份(賬號)查詢數據庫,如果查詢不到則用戶不存在
* 對輸入的密碼和數據庫密碼進行比對,如果一致則認證通過
*/
// 根據用戶賬號查詢數據庫
SysUser sysUser = this.findSysUserByUserCode(usercode);
if (sysUser == null) {
// 拋出異常
throw new CustomException("用戶賬號不存在");
}
// 數據庫密碼(MD5加密後的密碼)
String password_db = sysUser.getPassword();
// 對輸入的密碼和數據庫密碼進行比對,如果一致,認證通過
// 對頁面輸入的密碼進行MD5加密
String password_input_md5 = new MD5().getMD5ofStr(password);
if (!password_db.equalsIgnoreCase(password_input_md5)) {
//拋出異常
throw new CustomException("用戶名或密碼錯誤");
}
//得到用戶id
String userid = sysUser.getId();
//認證通過,返回用戶身份信息
ActiveUser activeUser = new ActiveUser();
activeUser.setUserid(userid);
activeUser.setUsercode(usercode);
activeUser.setUsername(sysUser.getUsername());
return activeUser;
}
public SysUser findSysUserByUserCode(String userCode) throws Exception {
SysUserExample sysUserExample = new SysUserExample();
SysUserExample.Criteria criteria = sysUserExample.createCriteria();
criteria.andUsercodeEqualTo(userCode);
List<SysUser> list = sysUserMapper.selectByExample(sysUserExample);
if (list != null && list.size() > 0) {
return list.get(0);
}
return null;
}
......
}
配置Service,往類Service中使用@Autowire 需要註冊Service 註冊有兩種方法(註解或配置文件),在架構時沒有配置掃描Service 需要在配置文件中註冊Service<!-- 認證和授權的Service -->
<bean id="sysService" class="liuxun.ssm.service.impl.SysServiceImpl"></bean>
controller(記錄Session)
//用戶登錄提交方法
@RequestMapping("/login")
public String login(HttpSession session,String randomcode,String usercode,String password) throws Exception{
// 校驗驗證碼,防止惡性攻擊
// 從Session中獲取正確的驗證碼
String validateCode = (String) session.getAttribute("validateCode");
//輸入的驗證碼和Session中的驗證碼進行對比
if (!randomcode.equalsIgnoreCase(validateCode)) {
//拋出異常
throw new CustomException("驗證碼輸入錯誤");
}
//調用Service校驗用戶賬號和密碼的正確性
ActiveUser activeUser = sysService.authenticat(usercode, password);
//如果Service校驗通過,將用戶身份記錄到Session
session.setAttribute("activeUser", activeUser);
//重定向到商品查詢頁面
return "redirect:/first.action";
}
用戶認證攔截器
anonymousURL.properties配置匿名URL
編寫身份認證攔截器
//用於用戶認證校驗、用戶權限校驗
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//得到請求的url
String url = request.getRequestURI();
//判斷是否是公開地址
//實際開發中需要將公開地址配置在配置文件中
//從配置文件中取出可以匿名訪問的URL
List<String> open_urls = ResourcesUtil.getKeyList("anonymousURL");
for (String open_url : open_urls) {
if (url.indexOf(open_url)>=0) {
//如果是公開地址 則放行
return true;
}
}
//判斷用戶身份在Session中是否存在
HttpSession session = request.getSession();
ActiveUser activeUser = (ActiveUser) session.getAttribute("activeUser");
//如果用戶身份在session中存在則放行
if (activeUser!=null) {
return true;
}
//執行到這裏攔截,跳轉到登錄頁面,用戶進行身份認證
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
//如果返回false表示攔截器不繼續執行handler,如果返回true表示放行
return false;
}
配置認證攔截器
<!-- 攔截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 用戶認證攔截 -->
<mvc:mapping path="/**"/>
<bean class="liuxun.ssm.controller.interceptor.LoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
用戶授權
commonURL.properties配置公用訪問地址
獲取用戶權限範圍的菜單
public class ActiveUser implements Serializable {
private String userid; //用戶id(主鍵)
private String usercode; // 用戶賬號
private String username; // 用戶姓名
private List<SysPermission> menus; //菜單
//......setter和getter方法
}
自定義權限Mapper<!-- 根據用戶id查詢菜單 -->
<select id="findMenuListByUserId" parameterType="string" resultType="liuxun.ssm.po.SysPermission">
SELECT
*
FROM
sys_permission
WHERE TYPE = 'menu'
AND id IN
(SELECT
sys_permission_id
FROM
sys_role_permission
WHERE sys_role_id IN
(SELECT
sys_role_id
FROM
sys_user_role
WHERE sys_user_id = #{userid}))
</select>
在SysPermissionMapperCustom.java接口中添加對應的方法public interface SysPermissionMapperCustom {
//根據用戶id查詢菜單
public List<SysPermission> findMenuListByUserId(String userid) throws Exception;
.......
}
在權限Service接口中添加對應的方法 在實現中注入SysPermissionMapperCustom@Override
public List<SysPermission> findMenuListByUserId(String userid) throws Exception {
return sysPermissionMapperCustom.findMenuListByUserId(userid);
}
獲取用戶權限範圍的URL
思路:public class ActiveUser implements Serializable {
private String userid; //用戶id(主鍵)
private String usercode; // 用戶賬號
private String username; // 用戶姓名
private List<SysPermission> menus; //菜單
private List<SysPermission> permissions; //權限
//...setter和getter方法
}
在SysPermissionMapperCustom.xml中添加根據用戶id查詢用戶權限的URL<!-- 根據用戶id查詢URL -->
<select id="findPermissionListByUserId" parameterType="string" resultType="liuxun.ssm.po.SysPermission">
SELECT
*
FROM
sys_permission
WHERE TYPE = 'permission'
AND id IN
(SELECT
sys_permission_id
FROM
sys_role_permission
WHERE sys_role_id IN
(SELECT
sys_role_id
FROM
sys_user_role
WHERE sys_user_id = #{userid}))
</select>
//根據用戶id查詢權限URL
public List<SysPermission> findPermissionListByUserId(String userid) throws Exception;
SysServiceImpl.java中添加如下內容@Override
public List<SysPermission> findPermissionListByUserId(String userid) throws Exception {
return sysPermissionMapperCustom.findPermissionListByUserId(userid);
}
用戶認證通過後取出菜單和URL放入Session
修改權限SysServiceImpl中用戶認證方法的代碼//得到用戶id
String userid = sysUser.getId();
//根據用戶id查詢菜單
List<SysPermission> menus = this.findMenuListByUserId(userid);
//根據用戶id查詢權限url
List<SysPermission> permissions = this.findPermissionListByUserId(userid);
//認證通過,返回用戶身份信息
ActiveUser activeUser = new ActiveUser();
activeUser.setUserid(userid);
activeUser.setUsercode(usercode);
activeUser.setUsername(sysUser.getUsername());
//放入權限範圍的菜單和url
activeUser.setMenus(menus);
activeUser.setPermissions(permissions);
菜單動態顯示
<c:if test="${activeUser.menus!=null }">
<ul>
<c:forEach items="${activeUser.menus }" var="menu">
<li><div>
<a title="${menu.name }" ref="1_1" href="#"
rel="${baseurl }/${menu.url }" icon="icon-log"><span
class="icon icon-log"> </span><span class="nav"><a href=javascript:addTab('${menu.name }','${baseurl }/${menu.url }')>${menu.name }</a></span></a>
</div></li>
</c:forEach>
</ul>
</c:if>
授權攔截器
public class PermissionInterceptor implements HandlerInterceptor{
//在執行handler之前執行的
//用於用戶認證校驗、用戶權限校驗
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//得到請求的url
String url = request.getRequestURI();
//判斷是否是公開地址
//實際開發中需要將公開地址配置在配置文件中
//從配置文件中取出可以匿名訪問的URL
List<String> open_urls = ResourcesUtil.getKeyList("anonymousURL");
for (String open_url : open_urls) {
if (url.indexOf(open_url)>=0) {
//如果是公開地址 則放行
return true;
}
}
//從配置文件中獲取公用訪問url
List<String> common_urls = ResourcesUtil.getKeyList("commonURL");
//遍歷公用地址 如果是公開地址則放行
for (String common_url : common_urls) {
if (url.indexOf(common_url)>0) {
//如果是公開,則放行
return true;
}
}
//判斷用戶身份在Session中是否存在
HttpSession session = request.getSession();
ActiveUser activeUser = (ActiveUser) session.getAttribute("activeUser");
//從Session中取出權限範圍的URL
List<SysPermission> permissions = activeUser.getPermissions();
for (SysPermission sysPermission : permissions) {
//權限url
String permission_url = sysPermission.getUrl();
if (url.indexOf(permission_url)>0) {
return true;
}
}
//執行到這裏攔截,跳轉到無權訪問的提示頁面
request.getRequestDispatcher("/WEB-INF/jsp/refuse.jsp").forward(request, response);
//如果返回false表示攔截器不繼續執行handler,如果返回true表示放行
return false;
}
......
}
配置授權攔截器
注意:要將授權攔截器配置在用戶認證攔截器的下邊,這是因爲SpringMVC攔截器的放行方法是順序執行的,如果是Struts的話則正好相反。<!-- 攔截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 用戶認證攔截 -->
<mvc:mapping path="/**"/>
<bean class="liuxun.ssm.controller.interceptor.LoginInterceptor"></bean>
</mvc:interceptor>
<mvc:interceptor>
<!-- 資源攔截 -->
<mvc:mapping path="/**"/>
<bean class="liuxun.ssm.controller.interceptor.PermissionInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
運行測試:此項目Demo已上傳GitHub(https://github.com/LX1993728/permission_web_noshiro)
package liuxun.ssm.po;
import java.io.Serializable;
import java.util.List;
/**
* 用戶身份信息,存入Session 由於Tomcat正常關閉時會將Session序列化的本地硬盤上,所以實現Serializable接口
* @author liuxun
*
*/
public class ActiveUser implements Serializable {
private static final long serialVersionUID = 1L;
private String userid; //用戶id(主鍵)
private String usercode; // 用戶賬號
private String username; // 用戶姓名
private List<SysPermission> menus; //菜單
private List<SysPermission> permissions; //權限
// 提供對應setter和getter方法
......
}
自定義權限的Mapper package liuxun.ssm.mapper;
import java.util.List;
import liuxun.ssm.po.SysPermission;
import liuxun.ssm.po.SysPermissionExample;
import org.apache.ibatis.annotations.Param;
/**
* 權限mapper
* @author liuxun
*
*/
public interface SysPermissionMapperCustom {
//根據用戶id查詢菜單
public List<SysPermission> findMenuListByUserId(String userid) throws Exception;
//根據用戶id查詢權限URL
public List<SysPermission> findPermissionListByUserId(String userid) throws Exception;
}
SysPermissionMapperCustom.xml<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="liuxun.ssm.mapper.SysPermissionMapperCustom">
<!-- 根據用戶id查詢菜單 -->
<select id="findMenuListByUserId" parameterType="string" resultType="liuxun.ssm.po.SysPermission">
SELECT
*
FROM
sys_permission
WHERE TYPE = 'menu'
AND id IN
(SELECT
sys_permission_id
FROM
sys_role_permission
WHERE sys_role_id IN
(SELECT
sys_role_id
FROM
sys_user_role
WHERE sys_user_id = #{userid}))
</select>
<!-- 根據用戶id查詢URL -->
<select id="findPermissionListByUserId" parameterType="string" resultType="liuxun.ssm.po.SysPermission">
SELECT
*
FROM
sys_permission
WHERE TYPE = 'permission'
AND id IN
(SELECT
sys_permission_id
FROM
sys_role_permission
WHERE sys_role_id IN
(SELECT
sys_role_id
FROM
sys_user_role
WHERE sys_user_id = #{userid}))
</select>
</mapper>
自定義權限的Service接口以及實現類package liuxun.ssm.service;
import java.util.List;
import liuxun.ssm.po.ActiveUser;
import liuxun.ssm.po.SysPermission;
import liuxun.ssm.po.SysUser;
/**
* 認證授權服務接口
* @author liuxun
*
*/
public interface SysService {
//根據用戶的身份和密碼進行認證,如果認證通過,返回用戶身份信息
public ActiveUser authenticat(String usercode,String password) throws Exception;
//根據用戶賬號查詢用戶信息
public SysUser findSysUserByUserCode(String userCode) throws Exception;
//根據用戶id查詢權限範圍內的菜單
public List<SysPermission> findMenuListByUserId(String userid) throws Exception;
//根據用戶id查詢權限範圍內的url
public List<SysPermission> findPermissionListByUserId(String userid) throws Exception;
}
SysServiceImpl.javapackage liuxun.ssm.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import liuxun.ssm.exception.CustomException;
import liuxun.ssm.mapper.SysPermissionMapperCustom;
import liuxun.ssm.mapper.SysUserMapper;
import liuxun.ssm.po.ActiveUser;
import liuxun.ssm.po.SysPermission;
import liuxun.ssm.po.SysUser;
import liuxun.ssm.po.SysUserExample;
import liuxun.ssm.service.SysService;
import liuxun.ssm.util.MD5;
public class SysServiceImpl implements SysService {
@Autowired
private SysUserMapper sysUserMapper;
@Autowired
private SysPermissionMapperCustom sysPermissionMapperCustom;
public ActiveUser authenticat(String usercode, String password) throws Exception {
/**
* 認證過程: 根據用戶身份(賬號)查詢數據庫,如果查詢不到則用戶不存在
* 對輸入的密碼和數據庫密碼進行比對,如果一致則認證通過
*/
// 根據用戶賬號查詢數據庫
SysUser sysUser = this.findSysUserByUserCode(usercode);
if (sysUser == null) {
// 拋出異常
throw new CustomException("用戶賬號不存在");
}
// 數據庫密碼(MD5加密後的密碼)
String password_db = sysUser.getPassword();
// 對輸入的密碼和數據庫密碼進行比對,如果一致,認證通過
// 對頁面輸入的密碼進行MD5加密
String password_input_md5 = new MD5().getMD5ofStr(password);
if (!password_db.equalsIgnoreCase(password_input_md5)) {
//拋出異常
throw new CustomException("用戶名或密碼錯誤");
}
//得到用戶id
String userid = sysUser.getId();
//根據用戶id查詢菜單
List<SysPermission> menus = this.findMenuListByUserId(userid);
//根據用戶id查詢權限url
List<SysPermission> permissions = this.findPermissionListByUserId(userid);
//認證通過,返回用戶身份信息
ActiveUser activeUser = new ActiveUser();
activeUser.setUserid(userid);
activeUser.setUsercode(usercode);
activeUser.setUsername(sysUser.getUsername());
//放入權限範圍的菜單和url
activeUser.setMenus(menus);
activeUser.setPermissions(permissions);
return activeUser;
}
public SysUser findSysUserByUserCode(String userCode) throws Exception {
SysUserExample sysUserExample = new SysUserExample();
SysUserExample.Criteria criteria = sysUserExample.createCriteria();
criteria.andUsercodeEqualTo(userCode);
List<SysUser> list = sysUserMapper.selectByExample(sysUserExample);
if (list != null && list.size() > 0) {
return list.get(0);
}
return null;
}
@Override
public List<SysPermission> findMenuListByUserId(String userid) throws Exception {
return sysPermissionMapperCustom.findMenuListByUserId(userid);
}
@Override
public List<SysPermission> findPermissionListByUserId(String userid) throws Exception {
return sysPermissionMapperCustom.findPermissionListByUserId(userid);
}
}
登錄控制器package liuxun.ssm.controller;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import liuxun.ssm.exception.CustomException;
import liuxun.ssm.po.ActiveUser;
import liuxun.ssm.service.SysService;
/**
* 登錄和退出
* @author liuxun
*
*/
@Controller
public class LoginController {
@Autowired
private SysService sysService;
//用戶登錄提交方法
@RequestMapping("/login")
public String login(HttpSession session,String randomcode,String usercode,String password) throws Exception{
// 校驗驗證碼,防止惡性攻擊
// 從Session中獲取正確的驗證碼
String validateCode = (String) session.getAttribute("validateCode");
//輸入的驗證碼和Session中的驗證碼進行對比
if (!randomcode.equalsIgnoreCase(validateCode)) {
//拋出異常
throw new CustomException("驗證碼輸入錯誤");
}
//調用Service校驗用戶賬號和密碼的正確性
ActiveUser activeUser = sysService.authenticat(usercode, password);
//如果Service校驗通過,將用戶身份記錄到Session
session.setAttribute("activeUser", activeUser);
//重定向到商品查詢頁面
return "redirect:/first.action";
}
//用戶退出
@RequestMapping("/logout")
public String logout(HttpSession session) throws Exception{
//session失效
session.invalidate();
//重定向到商品查詢頁面
return "redirect:/first.action";
}
}
身份認證攔截器LoginInterceptor.javapackage liuxun.ssm.controller.interceptor;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import liuxun.ssm.po.ActiveUser;
import liuxun.ssm.util.ResourcesUtil;
/**
* 測試攔截器1
* @author liuxun
*
*/
public class LoginInterceptor implements HandlerInterceptor{
//在執行handler之前執行的
//用於用戶認證校驗、用戶權限校驗
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//得到請求的url
String url = request.getRequestURI();
//判斷是否是公開地址
//實際開發中需要將公開地址配置在配置文件中
//從配置文件中取出可以匿名訪問的URL
List<String> open_urls = ResourcesUtil.getKeyList("anonymousURL");
for (String open_url : open_urls) {
if (url.indexOf(open_url)>=0) {
//如果是公開地址 則放行
return true;
}
}
//判斷用戶身份在Session中是否存在
HttpSession session = request.getSession();
ActiveUser activeUser = (ActiveUser) session.getAttribute("activeUser");
//如果用戶身份在session中存在則放行
if (activeUser!=null) {
return true;
}
//執行到這裏攔截,跳轉到登錄頁面,用戶進行身份認證
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
//如果返回false表示攔截器不繼續執行handler,如果返回true表示放行
return false;
}
//在執行handler返回modelAndView之前執行
//如果需要向頁面提供一些公用的數據或配置一些視圖信息,使用此方法實現 從modelAndView入手
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
System.out.println("HandlerInterceptor2...postHandle");
}
//執行handler之後執行此方法
//作爲系統統一異常處理,進行方法執行性能監控,在preHandler中設置一個時間點 在afterCompletion設置一個時間點 二者時間差就是執行時長
//實現系統,統一日誌記錄
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception modelAndView)
throws Exception {
System.out.println("HandlerInterceptor2...afterCompletion");
}
}
資源授權攔截器PermissionInterceptorpackage liuxun.ssm.controller.interceptor;
import java.security.acl.Permission;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import liuxun.ssm.po.ActiveUser;
import liuxun.ssm.po.SysPermission;
import liuxun.ssm.util.ResourcesUtil;
/**
* 授權攔截器
* @author liuxun
*
*/
public class PermissionInterceptor implements HandlerInterceptor{
//在執行handler之前執行的
//用於用戶認證校驗、用戶權限校驗
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//得到請求的url
String url = request.getRequestURI();
//判斷是否是公開地址
//實際開發中需要將公開地址配置在配置文件中
//從配置文件中取出可以匿名訪問的URL
List<String> open_urls = ResourcesUtil.getKeyList("anonymousURL");
for (String open_url : open_urls) {
if (url.indexOf(open_url)>=0) {
//如果是公開地址 則放行
return true;
}
}
//從配置文件中獲取公用訪問url
List<String> common_urls = ResourcesUtil.getKeyList("commonURL");
//遍歷公用地址 如果是公開地址則放行
for (String common_url : common_urls) {
if (url.indexOf(common_url)>0) {
//如果是公開,則放行
return true;
}
}
//判斷用戶身份在Session中是否存在
HttpSession session = request.getSession();
ActiveUser activeUser = (ActiveUser) session.getAttribute("activeUser");
//從Session中取出權限範圍的URL
List<SysPermission> permissions = activeUser.getPermissions();
for (SysPermission sysPermission : permissions) {
//權限url
String permission_url = sysPermission.getUrl();
if (url.indexOf(permission_url)>0) {
return true;
}
}
//執行到這裏攔截,跳轉到無權訪問的提示頁面
request.getRequestDispatcher("/WEB-INF/jsp/refuse.jsp").forward(request, response);
//如果返回false表示攔截器不繼續執行handler,如果返回true表示放行
return false;
}
//在執行handler返回modelAndView之前執行
//如果需要向頁面提供一些公用的數據或配置一些視圖信息,使用此方法實現 從modelAndView入手
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
System.out.println("HandlerInterceptor2...postHandle");
}
//執行handler之後執行此方法
//作爲系統統一異常處理,進行方法執行性能監控,在preHandler中設置一個時間點 在afterCompletion設置一個時間點 二者時間差就是執行時長
//實現系統,統一日誌記錄
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception modelAndView)
throws Exception {
System.out.println("HandlerInterceptor2...afterCompletion");
}
}
攔截器配置<!-- 攔截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 用戶認證攔截 -->
<mvc:mapping path="/**"/>
<bean class="liuxun.ssm.controller.interceptor.LoginInterceptor"></bean>
</mvc:interceptor>
<mvc:interceptor>
<!-- 資源攔截 -->
<mvc:mapping path="/**"/>
<bean class="liuxun.ssm.controller.interceptor.PermissionInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
使用URL攔截總結: