Apache Shiro(六)-基于URL配置权限
数据库
先准备数据库啦。
DROP DATABASE IF EXISTS shiro;
CREATE DATABASE shiro DEFAULT CHARACTER SET utf8;
USE shiro; drop table if exists user;
drop table if exists role;
drop table if exists permission;
drop table if exists user_role;
drop table if exists role_permission; create table user (
id bigint auto_increment,
name varchar(100),
password varchar(100),
salt varchar(100),
constraint pk_users primary key(id)
) charset=utf8 ENGINE=InnoDB; create table role (
id bigint auto_increment,
name varchar(100),
desc_ varchar(100),
constraint pk_roles primary key(id)
) charset=utf8 ENGINE=InnoDB; create table permission (
id bigint auto_increment,
name varchar(100),
desc_ varchar(100),
url varchar(100),
constraint pk_permissions primary key(id)
) charset=utf8 ENGINE=InnoDB; create table user_role (
id bigint auto_increment,
uid bigint,
rid bigint,
constraint pk_users_roles primary key(id)
) charset=utf8 ENGINE=InnoDB; create table role_permission (
id bigint auto_increment,
rid bigint,
pid bigint,
constraint pk_roles_permissions primary key(id)
) charset=utf8 ENGINE=InnoDB; INSERT INTO `permission` VALUES (1,'addProduct','增加产品','/addProduct');
INSERT INTO `permission` VALUES (2,'deleteProduct','删除产品','/deleteProduct');
INSERT INTO `permission` VALUES (3,'editeProduct','编辑产品','/editeProduct');
INSERT INTO `permission` VALUES (4,'updateProduct','修改产品','/updateProduct');
INSERT INTO `permission` VALUES (5,'listProduct','查看产品','/listProduct');
INSERT INTO `permission` VALUES (6,'addOrder','增加订单','/addOrder');
INSERT INTO `permission` VALUES (7,'deleteOrder','删除订单','/deleteOrder');
INSERT INTO `permission` VALUES (8,'editeOrder','编辑订单','/editeOrder');
INSERT INTO `permission` VALUES (9,'updateOrder','修改订单','/updateOrder');
INSERT INTO `permission` VALUES (10,'listOrder','查看订单','/listOrder');
INSERT INTO `role` VALUES (1,'admin','超级管理员');
INSERT INTO `role` VALUES (2,'productManager','产品管理员');
INSERT INTO `role` VALUES (3,'orderManager','订单管理员');
INSERT INTO `role_permission` VALUES (1,1,1);
INSERT INTO `role_permission` VALUES (2,1,2);
INSERT INTO `role_permission` VALUES (3,1,3);
INSERT INTO `role_permission` VALUES (4,1,4);
INSERT INTO `role_permission` VALUES (5,1,5);
INSERT INTO `role_permission` VALUES (6,1,6);
INSERT INTO `role_permission` VALUES (7,1,7);
INSERT INTO `role_permission` VALUES (8,1,8);
INSERT INTO `role_permission` VALUES (9,1,9);
INSERT INTO `role_permission` VALUES (10,1,10);
INSERT INTO `role_permission` VALUES (11,2,1);
INSERT INTO `role_permission` VALUES (12,2,2);
INSERT INTO `role_permission` VALUES (13,2,3);
INSERT INTO `role_permission` VALUES (14,2,4);
INSERT INTO `role_permission` VALUES (15,2,5);
INSERT INTO `role_permission` VALUES (50,3,10);
INSERT INTO `role_permission` VALUES (51,3,9);
INSERT INTO `role_permission` VALUES (52,3,8);
INSERT INTO `role_permission` VALUES (53,3,7);
INSERT INTO `role_permission` VALUES (54,3,6);
INSERT INTO `role_permission` VALUES (55,3,1);
INSERT INTO `role_permission` VALUES (56,5,11);
INSERT INTO `user` VALUES (1,'zhang3','a7d59dfc5332749cb801f86a24f5f590','e5ykFiNwShfCXvBRPr3wXg==');
INSERT INTO `user` VALUES (2,'li4','43e28304197b9216e45ab1ce8dac831b','jPz19y7arvYIGhuUjsb6sQ==');
INSERT INTO `user_role` VALUES (43,2,2);
INSERT INTO `user_role` VALUES (45,1,1);
点击展开
基于前面的知识点继续进行
下面只展示基于前面的代码做修改
PageController.java
首先是PageController.java 里原本通过注解方式的@RequiresPermissions和@RequiresRoles 注释掉了
package com.how2java.controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; //专门用于显示页面的控制器
@Controller
@RequestMapping("")
public class PageController { @RequestMapping("index")
public String index(){
return "index";
} // @RequiresPermissions("deleteOrder")
@RequestMapping("deleteOrder")
public String deleteOrder(){
return "deleteOrder";
}
// @RequiresRoles("productManager")
@RequestMapping("deleteProduct")
public String deleteProduct(){
return "deleteProduct";
}
@RequestMapping("listProduct")
public String listProduct(){
return "listProduct";
} @RequestMapping(value="/login",method=RequestMethod.GET)
public String login(){
return "login";
}
@RequestMapping("unauthorized")
public String noPerms(){
return "unauthorized";
} }
点击展开
PermissionService.java
增加了两个方法 needInterceptor,listPermissionURLs
package com.how2java.service; import java.util.List;
import java.util.Set; import com.how2java.pojo.Permission;
import com.how2java.pojo.Role; public interface PermissionService {
public Set<String> listPermissions(String userName); public List<Permission> list(); public void add(Permission permission); public void delete(Long id); public Permission get(Long id); public void update(Permission permission); public List<Permission> list(Role role); public boolean needInterceptor(String requestURI); public Set<String> listPermissionURLs(String userName); }
点击展开
PermissionServiceImpl.java
为两个方法 needInterceptor,listPermissionURLs 增加了实现
needInterceptor 表示是否要进行拦截,判断依据是如果访问的某个url,在权限系统里存在,就要进行拦截。 如果不存在,就放行了。
这一种策略,也可以切换成另一个,即,访问的地址如果不存在于权限系统中,就提示没有拦截。 这两种做法没有对错之分,取决于业务上希望如何制定权限策略。
listPermissionURLs(User user) 用来获取某个用户所拥有的权限地址集合
package com.how2java.service.impl; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import com.how2java.mapper.PermissionMapper;
import com.how2java.mapper.RolePermissionMapper;
import com.how2java.pojo.Permission;
import com.how2java.pojo.PermissionExample;
import com.how2java.pojo.Role;
import com.how2java.pojo.RolePermission;
import com.how2java.pojo.RolePermissionExample;
import com.how2java.service.PermissionService;
import com.how2java.service.RoleService;
import com.how2java.service.UserService; @Service
public class PermissionServiceImpl implements PermissionService { @Autowired
PermissionMapper permissionMapper;
@Autowired
UserService userService;
@Autowired
RoleService roleService;
@Autowired
RolePermissionMapper rolePermissionMapper; @Override
public Set<String> listPermissions(String userName) {
Set<String> result = new HashSet<>();
List<Role> roles = roleService.listRoles(userName); List<RolePermission> rolePermissions = new ArrayList<>(); for (Role role : roles) {
RolePermissionExample example = new RolePermissionExample();
example.createCriteria().andRidEqualTo(role.getId());
List<RolePermission> rps = rolePermissionMapper.selectByExample(example);
rolePermissions.addAll(rps);
} for (RolePermission rolePermission : rolePermissions) {
Permission p = permissionMapper.selectByPrimaryKey(rolePermission.getPid());
result.add(p.getName());
} return result;
} @Override
public void add(Permission u) {
permissionMapper.insert(u);
} @Override
public void delete(Long id) {
permissionMapper.deleteByPrimaryKey(id);
} @Override
public void update(Permission u) {
permissionMapper.updateByPrimaryKeySelective(u);
} @Override
public Permission get(Long id) {
return permissionMapper.selectByPrimaryKey(id);
} @Override
public List<Permission> list() {
PermissionExample example = new PermissionExample();
example.setOrderByClause("id desc");
return permissionMapper.selectByExample(example); } @Override
public List<Permission> list(Role role) {
List<Permission> result = new ArrayList<>();
RolePermissionExample example = new RolePermissionExample();
example.createCriteria().andRidEqualTo(role.getId());
List<RolePermission> rps = rolePermissionMapper.selectByExample(example);
for (RolePermission rolePermission : rps) {
result.add(permissionMapper.selectByPrimaryKey(rolePermission.getPid()));
} return result;
} @Override
public boolean needInterceptor(String requestURI) {
List<Permission> ps = list();
for (Permission p : ps) {
if (p.getUrl().equals(requestURI))
return true;
}
return false;
} @Override
public Set<String> listPermissionURLs(String userName) {
Set<String> result = new HashSet<>();
List<Role> roles = roleService.listRoles(userName); List<RolePermission> rolePermissions = new ArrayList<>(); for (Role role : roles) {
RolePermissionExample example = new RolePermissionExample();
example.createCriteria().andRidEqualTo(role.getId());
List<RolePermission> rps = rolePermissionMapper.selectByExample(example);
rolePermissions.addAll(rps);
} for (RolePermission rolePermission : rolePermissions) {
Permission p = permissionMapper.selectByPrimaryKey(rolePermission.getPid());
result.add(p.getUrl());
} return result;
} }
点击展开
URLPathMatchingFilter.java
PathMatchingFilter 是shiro 内置过滤器 PathMatchingFilter 继承了这个它。
基本思路如下:
1. 如果没登录就跳转到登录
2. 如果当前访问路径没有在权限系统里维护,则允许访问
3. 当前用户所拥有的权限如何不包含当前的访问地址,则跳转到/unauthorized,否则就允许访问
package com.how2java.filter; import java.util.Set; import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.PathMatchingFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired; import com.how2java.service.PermissionService; public class URLPathMatchingFilter extends PathMatchingFilter {
@Autowired
PermissionService permissionService; @Override
protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue)
throws Exception {
String requestURI = getPathWithinApplication(request); System.out.println("requestURI:" + requestURI); Subject subject = SecurityUtils.getSubject();
// 如果没有登录,就跳转到登录页面
if (!subject.isAuthenticated()) {
WebUtils.issueRedirect(request, response, "/login");
return false;
} // 看看这个路径权限里有没有维护,如果没有维护,一律放行(也可以改为一律不放行)
boolean needInterceptor = permissionService.needInterceptor(requestURI);
if (!needInterceptor) {
return true;
} else {
boolean hasPermission = false;
String userName = subject.getPrincipal().toString();
Set<String> permissionUrls = permissionService.listPermissionURLs(userName);
for (String url : permissionUrls) {
// 这就表示当前用户有这个权限
if (url.equals(requestURI)) {
hasPermission = true;
break;
}
} if (hasPermission)
return true;
else {
UnauthorizedException ex = new UnauthorizedException("当前用户没有访问路径 " + requestURI + " 的权限"); subject.getSession().setAttribute("ex", ex); WebUtils.issueRedirect(request, response, "/unauthorized");
return false;
} } }
}
点击展开
applicationContext-shiro.xml
首先声明URLPathMatchingFilter 过滤器
<bean id="urlPathMatchingFilter" class="com.how2java.filter.URLPathMatchingFilter"/>
在shiro中使用这个过滤器
<entry key="url" value-ref="urlPathMatchingFilter" />
过滤规则是所有访问
/** = url
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans" xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd"> <!-- url过滤器 -->
<bean id="urlPathMatchingFilter" class="com.how2java.filter.URLPathMatchingFilter"/> <!-- 配置shiro的过滤器工厂类,id- shiroFilter要和我们在web.xml中配置的过滤器一致 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- 调用我们配置的权限管理器 -->
<property name="securityManager" ref="securityManager" />
<!-- 配置我们的登录请求地址 -->
<property name="loginUrl" value="/login" />
<!-- 如果您请求的资源不再您的权限范围,则跳转到/403请求地址 -->
<property name="unauthorizedUrl" value="/unauthorized" />
<!-- 退出 -->
<property name="filters">
<util:map>
<entry key="logout" value-ref="logoutFilter" />
<entry key="url" value-ref="urlPathMatchingFilter" />
</util:map>
</property>
<!-- 权限配置 -->
<property name="filterChainDefinitions">
<value>
<!-- anon表示此地址不需要任何权限即可访问 -->
/login=anon
/index=anon
/static/**=anon
<!-- 只对业务功能进行权限管理,权限配置本身不需要没有做权限要求,这样做是为了不让初学者混淆 -->
/config/**=anon
/doLogout=logout
<!--所有的请求(除去配置的静态资源请求或请求地址为anon的请求)都要通过过滤器url -->
/** = url
</value>
</property>
</bean>
<!-- 退出过滤器 -->
<bean id="logoutFilter" class="org.apache.shiro.web.filter.authc.LogoutFilter">
<property name="redirectUrl" value="/index" />
</bean> <!-- 会话ID生成器 -->
<bean id="sessionIdGenerator"
class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator" />
<!-- 会话Cookie模板 关闭浏览器立即失效 -->
<bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg value="sid" />
<property name="httpOnly" value="true" />
<property name="maxAge" value="-1" />
</bean>
<!-- 会话DAO -->
<bean id="sessionDAO"
class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
<property name="sessionIdGenerator" ref="sessionIdGenerator" />
</bean>
<!-- 会话验证调度器,每30分钟执行一次验证 ,设定会话超时及保存 -->
<bean name="sessionValidationScheduler"
class="org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler">
<property name="interval" value="1800000" />
<property name="sessionManager" ref="sessionManager" />
</bean>
<!-- 会话管理器 -->
<bean id="sessionManager"
class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<!-- 全局会话超时时间(单位毫秒),默认30分钟 -->
<property name="globalSessionTimeout" value="1800000" />
<property name="deleteInvalidSessions" value="true" />
<property name="sessionValidationSchedulerEnabled" value="true" />
<property name="sessionValidationScheduler" ref="sessionValidationScheduler" />
<property name="sessionDAO" ref="sessionDAO" />
<property name="sessionIdCookieEnabled" value="true" />
<property name="sessionIdCookie" ref="sessionIdCookie" />
</bean> <!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="databaseRealm" />
<property name="sessionManager" ref="sessionManager" />
</bean>
<!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) -->
<bean
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod"
value="org.apache.shiro.SecurityUtils.setSecurityManager" />
<property name="arguments" ref="securityManager" />
</bean> <!-- 密码匹配器 -->
<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="md5"/>
<property name="hashIterations" value="2"/>
<property name="storedCredentialsHexEncoded" value="true"/>
</bean> <bean id="databaseRealm" class="com.how2java.realm.DatabaseRealm">
<property name="credentialsMatcher" ref="credentialsMatcher"/>
</bean> <!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
</beans>
点击展开
jsp 们
jsp前端页面这里就不贴了。先要的到下面下载。
关于角色
在本知识点中,权限通过url进行灵活配置了。 但是角色还没有和url对应起来。 为什么不把角色也对应起来呢?
从代码开发的角度讲是可以做的,无非就是在 role表上增加一个url 字段。 但是从权限管理本身的角度看,当一个url 既对应权限表的数据,又对应角色表的数据,反而容易产生混淆。
反倒是现在这种,url地址,仅仅和权限表关联起来,在逻辑上明晰简单,也更容易维护。 所以就放弃了角色表也进行url维护的做法了。
结束
大家可以跑起来试一下。
代码下载地址:https://gitee.com/fengyuduke/my_open_resources/blob/master/shiro-url.zip
另外:项目所需jar包下载地址 https://gitee.com/fengyuduke/my_open_resources/tree/jarPackage/
Apache Shiro(六)-基于URL配置权限的更多相关文章
- SpringBoot整合Shiro实现基于角色的权限访问控制(RBAC)系统简单设计从零搭建
SpringBoot整合Shiro实现基于角色的权限访问控制(RBAC)系统简单设计从零搭建 技术栈 : SpringBoot + shiro + jpa + freemark ,因为篇幅原因,这里只 ...
- 在ASP.NET MVC中实现基于URL的权限控制
本示例演示了在ASP.NET MVC中进行基于URL的权限控制,由于是基于URL进行控制的,所以只能精确到页.这种权限控制的优点是可以在已有的项目上改动极少的代码来增加权限控制功能,和项目本身的耦合度 ...
- [Shiro] - 基于URL配置动态权限
基于shiro进阶 更改了数据库表 之前的PageController是通过@RequiresPermissions和@RequiresRoles进行是否有权限/是否有角色的判定调用@RequestM ...
- Apache Shiro(五)-登录认证和权限管理ssm
创建一个web动态项目 jar包 web.xml web.xml做了如下几件事情1. 指定spring的配置文件有两个 applicationContext.xml: 用于链接数据库的 applica ...
- Apache Shiro(二)-登录认证和权限管理数据库操作
数据库支持 在上一篇中使用ini 配置文件进行了相关权限数据的配置. 但是实际工作中,我们都会把权限相关的内容放在数据库里. 所以本知识点讲解如何放在数据库里来撸. RBAC 概念 RBAC 是当下权 ...
- Spring Security 基于URL的权限判断
1. FilterSecurityInterceptor 源码阅读 org.springframework.security.web.access.intercept.FilterSecurityI ...
- 基于 URL 的权限控制
先不用框架,自己实现一下 数据库 /* SQLyog v10.2 MySQL - 5.1.72-community : Database - shiro *********************** ...
- 基于url的权限管理
基于url权限管理流程 完成权限管理的数据模型创建. 1. 系统登陆 系统 登陆相当 于用户身份认证,用户成功,要在session中记录用户的身份信息. 操作流程: 用户进行登陆页面 输入用户 ...
- shiro-5基于url的权限管理
1.1 搭建环境 1.1.1 数据库 mysql5.1数据库中创建表:用户表.角色表.权限表(实质上是权限和资源的结合 ).用户角色表.角色权限表. 完成权限管理的数据模型创建. 1.1.2 开发环境 ...
随机推荐
- 19-格子游戏(hdu2147博弈)
http://acm.hdu.edu.cn/showproblem.php?pid=2147 kiki's game Time Limit: 5000/1000 MS (Java/Others) ...
- 1.scala基础语法总结
Scala基础语法总结:Scala 与 Java 的最大区别是:Scala 语句末尾的分号 ; 是可选的.如果一行里写多个语句那么分号是需要的 val s = "菜鸟教程"; pr ...
- 使对象可以像数组一样foreach循环,要求属性必须是私有的(写个类实现Iterator接口)
<?php class Test implements Iterator { ,,,,); public function __construct() { } // 重置,将数组内部指针指向第一 ...
- 利用URL重写实现Session跟踪
Servlet规范中引入了一种补充的会话管理机制,它允许不支持Cookie的浏览器也可以与WEB服务器保持连续的会话.这种补充机制要求在响应消息的实体内容中必须包含下一次请求的超链接,并将会话标识号作 ...
- Linux下面rpm命令和mount命令详解
在Linux下面我们经常会安装一些软件包,还有挂载命令.接下来,我们通过一些实例来演示这些命令的使用.. 第一步:我们先在linux下面挂载光盘,先进入到根目录,然后切换到根下面的/mnt目录,因为/ ...
- (转)XSS危害——session劫持
原文地址:http://www.cnblogs.com/dolphinX/p/3403027.html 在跨站脚本攻击XSS中简单介绍了XSS的原理及一个利用XSS盗取存在cookie中用户名和密码的 ...
- ArcGIS Desktop和Engine中对点要素图层Graduated Symbols渲染的实现 Rotation Symbol (转)
摘要 ArcGIS中,对于要素图层的渲染,支持按照要素字段的值渲染要素的大小,其中Graduated Symbols可以对大小进行分级渲染.在个人开发系统的过程中,也可以用来美化数据显 ...
- spring是如何由请求地址找到对应的control的
spring先将所有的action bean放进内存中,然后根据@RequestMapping(value = "/", method = RequestMethod.GET)这种 ...
- 精心收集的 48 个 JavaScript 代码片段,仅需 30 秒就可理解!(转载)
Anagrams of string(带有重复项) 使用递归.对于给定字符串中的每个字母,为字母创建字谜.使用map()将字母与每部分字谜组合,然后使用reduce()将所有字谜组合到一个数组中,最基 ...
- 使用 wget 下载需要 cookie 认证的网站
.使用火狐,安装 Export Cookies 插件 2.登录网站,点菜单"工具-Export Cookies..",保存 cookies.txt 到自己的文件夹 3.把 cookies.t ...