我是靠谱客的博主 大意眼睛,最近开发中收集的这篇文章主要介绍权限Shiro框架怎么在项目中使用?,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

一、客户关系管理系统项目:

组织机构模块:
员工管理 、 部门管理
、主题设置
权限模块:
菜单管理 、权限管理 、 资源管理 、角色管理
基础数据模块:
数据字典明细 、 数据字典目录
高级业务模块:
订单管理
、合同管理
、保修管理
客户模块:
客户管理
、 潜在客户 、 客户跟进历史 、客户资源池
、潜在客户开发 、 客户移交

二、开发该项目的工具:

开发工具:
eclipse
开发语言 : java语言
javascript语言
网页动态技术: jsp
数据库 :
MySQL
前台展示数据框架: EasyUI框架
采用SSM项目集成框架
Spring : 管理整个项目
Spring-Mvc : SpringMVC是一个基于MVC模式的WEB框架,它解决WEB开发中常见
的问题(参数接收、文件上传/下载、表单验证、国际化、等等),使用非常简
单,SpringMVC作为Spring中的一个模块,可以与Spring无缝集成。 前台与后台程序
技术。
Mybatis :
java代码连接数据库的一种框架技术
Shiro框架:一种安全shiro框架
Activiti:
多个人一起做一件事情的步骤,这个步骤可以让计算机理解的步骤
===========================================================
在这里给大家简单介绍一下权限模块的大体思路:
不同的用户拥有不同的角色,不同的角色拥有不同的权限,一个权限对应了一个资源/菜单
权限控制的内容:
页面菜单的显示:
页面按钮的显示:
身份认证:
授权:
数据模型(重要模型):
主要功能:
添加员工的时候赋予所对应的角色
添加角色的时候赋予所对应的权限
那么员工就可以根据不同的角色访问不同的权限资源。

三、登录权限

 A 、 完成集成shiro配置文件
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置核心对象securityManager -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="ssmRealm"></property>
</bean>
<!-- 自定义的Realm -->
<bean id="ssmRealm" class="cn.itsource.crm.shiro.realm.MyRealm">
<!-- 比较器 -->
<property name="credentialsMatcher">
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<!-- 加密的算法 -->
<property name="hashAlgorithmName" value="MD5"></property>
<!-- 加密的次数 -->
<property name="hashIterations" value="1000"></property>
</bean>
</property>
</bean>
<!-- 过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<!--
登录页面 访问需要认证才能访问的资源时,如果没有认证,跳转到登录界面 -->
<property name="loginUrl" value="/login.jsp"/>
<!--
认证成功后的页面 -->
<property name="successUrl" value="/main"/>
<!--
当访问需要授权才能访问的资源时,如果没有权限,就跳转到这个页面 -->
<property name="unauthorizedUrl" value="/unauthorized.jsp"/>
<property name="filterChainDefinitionMap" ref="filterChainDefinitionMap"></property>
<property name="filters">
<map>
<entry key="crmPerms">
<bean class="cn.itsource.crm.filter.CrmAccessControllerFilter"></bean>
</entry>
</map>
</property>
</bean>
<!-- 工厂bean -->
<bean id="myFactory" class="cn.itsource.crm.shiro.factory.FilterChainDefinitionMapFactoryBean"></bean>
<bean id="filterChainDefinitionMap" factory-bean="myFactory" factory-method="getFilterChainDefinitionMap"></bean>
</beans>
B
、在apolicationContext.xml中引入shiro.xml文件
<import resource="classpath:applicationContext-*.xml"/>
C 、 在web.xml中配置
<!--
shiro的代理过滤器
filter-name的值要和applicationContext-shiro.xml中过滤器的id一致
-->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--
会话超时
-->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
数据库密码和登录密码必须保证是加密加盐加次数

3.1 登录页面login.jsp

写一个简单的登录界面
可以做按回车键登录功能
给登录按钮绑定keyup事件,判断event.keyCode是否等于13,如果等于。提交表单
<script type="text/javascript">
$(document.documentElement).on("keyup", function(event) {
//console.debug(event.keyCode);
var keyCode = event.keyCode;
console.debug(keyCode);
if (keyCode === 13) { // 捕获回车
submitForm(); // 提交表单
}
});
超时功能
// 检查自己是否是顶级页面
if (top != window) {// 如果不是顶级
//把子页面的地址,赋值给顶级页面显示
window.top.location.href = window.location.href;
}

3.2 编写remal

	自定义一个remal去继承AuthorizingRealm,实现两个方法,一个身份认证方法,授权方法。
身份认证思路:
从token对象获取登录用户
再根据登录用户获取登录名
根据登录名查询数据库返回一个用户
再这里先判断用户是否存在
把该用户封装到info对象中,注意:参数 加密加盐加次数
这里其实把token对象中的用户和info对象中的用户做比较,那么就需要一个比较器,
在上面的shiro.xml已经配置了。
接下来写一个LoginController
思路:
获取当前登录用户
判断是否被认证,如果未被认证,把用户名和密码封装到token对象中,再调用登录
方法如果登录成功,需要把当前登录用户信息存在session中,在这里,可以写一个
工具类(UserContext) 提供两个方法,
1、把当前登录用户信息存入到seesio中,
2、从session取出登录用户信息,这样做的话方便我们在任何地方调用,
因为很多地方都需要使用它。

3.3 高级功能:


登录用户显示:
就是显示当前登录显示在本系统中,此时就可以再jsp页面中直接从session获取了
用户注销:
非常简单,直接使用shiro框架的logout就可以注销了
回车登录:
上面已经详解
登录超时处理:
上面已经详解

=====================================================

四、权限设计:

为什么需要权限?
对于我们的系统的一些功能只有特定的角色才能访问资源,不同的用户拥有不同的角色,
但是呢,不同的角色又拥有不同的权限,因此访问的不同用户访问系统看到的就是不同的
资源,权限其实就是给资源加锁,
权限相关实体关系
用户== 多对多==角色==多对多==权限===资源
其实在这里权限和资源之间存在三种实体关系,一对多、一对多、多对多。
今天小编就采用了一对一给大家讲解一下。

4.1 权限数据怎么添加?

	一个要控制资源就有一个权限,那么权限数据怎么来?
手动添加:在页面写一个添加按钮,一条一条数据添加
动态添加:在页面写一个一键加载资源按钮,可以把所有数据添加到数据库,(采用)
思路:
自定义一个注解PermissionResource,然后标注在需要管理的资源上
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PermissionResource {
String name();
String sn();
}

4.2 写一个一键加资源权限方法

思路:
//一键加载资源权限路径
@RequestMapping("/load")
@ResponseBody
public AjaxResult loadResource(HttpServletRequest req){
List<Permission> list;
try {
list = new ArrayList<>();
//扫描cn.itsource.crm.controller包下面的所有类
// 如果有Class.forName(""); 包名+类名
//获取WEB-INF/classes/cn/itsource/crm/controller包下面的所有.class文件,绝对路径
//一会下面需要拼接起来
String packageName="cn.itsource.crm.controller";
//获取绝对路径
String contextPath = req.getRealPath("WEB-INF/classes/cn/itsource/crm/controller");
//创建一个file
File file = new File(contextPath);
//遍历出该文件夹下面所有的.class文件
String[] listClasses = file.list();
for (String string : listClasses) {
/*System.out.println(string);*/ // PermissionController.class
}
//获取类的完全限定名
String [] classNames = new String[listClasses.length];
for(int i=0 ; i<listClasses.length;i++ ){
classNames[i] = packageName+"."+listClasses[i].split("\.")[0];
}
//所有的controller的class对象
List<Class> classList = new ArrayList<>();
//遍历类的完全限定名
for (String string : classNames) {
Class c =Class.forName(string);
classList.add(c);
}
//扫描每个class上的permissionResource注解 使用循环扫描
//封装到Permission中,一个权限封装一个Permission ,把它保存到数据库
//先扫描类上面的requestMapping注解的值
for (Class class1 : classList) {
String classPath = "";
//先判断是否有注解
if(class1.isAnnotationPresent(RequestMapping.class)){
//扫描 类上面的Requestmapping注解的值
sn
name
RequestMapping requestMapping = (RequestMapping)class1.getAnnotation(RequestMapping.class);
classPath = requestMapping.value()[0];
//permission
}
//再继续扫描方法上的requestMapping和自己写的注解PermissionResource
Method[] methods = class1.getMethods();
String methodPath = "";
for (Method method1 : methods) {
//获取方法上有自己写的PermissionResource注解的注解
PermissionResource annotation = method1.getAnnotation(PermissionResource.class);
//判断,如果不为空,那么就获取方法上的自定义注解
if(annotation != null){
//System.out.println(method1.getName());
RequestMapping annotation2 = method1.getAnnotation(RequestMapping.class);
methodPath = annotation2.value()[0];
//资源
String resource =classPath + methodPath;
//继续获取权限名称 和标识
String sn = annotation.sn();
String name = annotation.name();
//创建权限对象
Permission permission = new Permission(sn , name , resource);
//把权限对象添加到list中
list.add(permission);
}
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return new AjaxResult("加载失败"+e.getMessage());
}
//将list中的所有权限信息添加到数据库
permissionService.loadPermission(list);
return
new AjaxResult();
}

4.3 Service层

接下来在service写一个loadPermission(List<Permission> list){
方案一:
先删除权限表
再添加所有权限
如果这样的话思路没有问题,但是数据库中权限表的id是自增的,对应
不上role_permission表的id,到时候找不到,无法显示。
方案二:
因此采用这种方案:
不用删除权限表中的数据,如果权限表中已经加载过了,就不需要重复加载了
加载未加载过的权限就OK了。
	@Override
@Transactional
public void loadPermission(List<Permission> list) {
//查询数据库中旧的权限
List<Permission> oldPermissions = permissionMapper.selectAll();
//获取list中比oldPermissions多出来的权限
//两个集合取差集
list.removeAll(oldPermissions);
//添加未有的权限
for (Permission permission : list) {
permissionMapper.insert(permission);
}
还需要注意:在perimssion中需要
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Permission other = (Permission) obj;
if (sn == null) {
if (other.sn != null)
return false;
} else if (!sn.equals(other.sn))
return false;
return true;
}
}
}

4.4 角色列表:

	功能:添加角色的时候并且赋予该角色的拥有的权限
前台:点击添加,弹出一个模态框
模态框中有表单和数据表格
分为上下两部分,上是表单,下是数据表格
数据表格分为左右两部分,左是已选择权限,右是所有权限
当点击保存的时候,把表单中的数据个已选择权限一起添加到
数据库,这样的话就实现添加角色的时候赋予了权限功能

4.4.1 添加、删除、修改思路

4.4.1.1 添加:

	前台:当点击保存的时候,是同时保存表单数据和数据表格数据,因为我使用的easyUi框架,
表单中的数据可以直提交,但是呢 ,数据表格不会提交,那么需要额外参数提交就行了。
点击添加需要先清空数据
 //清空左侧datagrid
selectPermission.datagrid("loadData",{
total:0,
rows:[]
})
/*
alert(0) */
//添加需要先清空表单
roleForm.form("clear");
//把dialog模态框打开、居中、设置标题
roleDialog.dialog("open").dialog("center").dialog("setTitle","添加角色");
onSubmit: function(param){
/获取选中的那一行
var rows = selectPermission.datagrid("getRows")
console.debug(rows.id);
//传额外的参数 就是数据表单中数据
for(var i in rows){
param["permissions["+i+"].id"]= rows[i].id;
}
后台:
调用保存方法,注意:在这里先保存角色表,然后在保存中间表,那么中间表怎么保存呢,
有两个字段id,角色id和权限id, 先从role中获取所有权限,遍历它,那么就可以得到权限的id了,
在创建中间表对象,把角色id和权限id设置到中间表对象中,然后再把中间表对象添加到list中,
遍历list,再调用保存方法把它保存到中间表的数
据添加到数据库。
@Override
@Transactional
public void add(Role role) {
//先添加t_role
roleMapper.insert(role);
//在添加t_role_permission
List<RolePermission> list = new ArrayList<>();
for (Permission ps : role.getPermissions()) {
RolePermission rp = new RolePermission();
rp.setRoleId(role.getId());
rp.setPermissionId(ps.getId());
//把rp添加到list中
list.add(rp);
}
//添加中间表
for (RolePermission rolePermission : list) {
rolePermissionMapper.insert(rolePermission);
}
}

4.4.1.2 修改思路:


前台:
点击修改,需要把数据回显在模态框中的表单和数据表格中,
//回显表单 from('load' , row)
roleForm.form("load" , row);
//回显数据表格
selectPermission.datagrid("loadData" , {
total:row.permissions.length,
rows:row.permissions,
})
再点击保存,调用修改方法
后台:
先修改角色表
再清空中间表的信息
注意:在这里,清空中间表的时候,是根据角色表的id
写sql语句到数据库进行删除的
再添加中间表

4.4.1.3 删除思路:


前台:
先选中一行,点击删除,调用后台删除方法
后台:
先删除中间表
注意:在这里,清空中间表的时候,是根据角色表
id写sql语句到数据库进行删除的
在删除角色表

=====================================================

五、授权操作:

	授权:
回顾:
我们使用shiro做了身份认证,还没有进行授权操作

5.1 如何使用shiro授权?

	权限拦截:
告诉shiro哪些资源需要什么样的权限才能访问。
/Dept/delete
===
dept:delete
两种方式:
Xml中写死:	不好,因为数据库中有很多路径权限,我们
需要查询出来
动态加载:
写一个MapfactoryBean类
提供一个public
Map<String
, Object> getMap(){ //返回一个map
Map<String , String > map = new LinkedHashMap<>();
在这里从数据库中查询出来的权限放在map中
配置权限拦截过滤器 查询所有的权限,遍历出来,把路径url
和sn放在map 中, 注意: 需要拼接,这样的话访问任何都没
有权限,因为还没有告诉shiro
那么在之前写的身份认证类现在需要继承AuthorizingRealm
重写两个方法:
身份认证方法:加密加盐加次数 ,昨天已经操作了。
shiro方法:
告诉shiro当前登录人的用户都有哪些权限
那么service应该提供个方法:通过当前登录人返回所有的
权限,需要
五张表
:
根据当前登录人的id查询出当前登录的所有权
限 : 映射
在这里查询出来之后,把所有权限字符串封装到info对象
中。
Info.setStringPermissions() //不推荐使用
遍历:把info.addStringPermission(遍历出的.getSn())
//返回info
}

5.2 授权:

 告诉shiro当前登录的用户都哪些权限?
Dept:save
dept:page
dept:delete
实现方式: 在reaml中的info对象,
可以控制:
URL地址 控制器的方法 也相当于URL地址
有权限显示该菜单,没有权限不显示该菜单
页面的按钮,没有权限不显示该按钮
数据模型(重要模型)
A只能看到A用户的顾客 B只能看到B用户的客
管理员可以看到A用户的顾客也可以看到B顾客
shiro是Java中一种安全框架 ,怎么实现的?
作用:身份认证、授权、会话管理、密码学
Spring security :一种重量级的框架,但是功能要强大一些
Apache shiro: 他是一种轻量级框架,用起来比较简单 相比security学习成本低一些

5.3 权限和菜单/资源:

	怎么关联起来:一对一关系
在权限表中添加一个menu_id外键 对应菜单中的id	,
在这里,有Url的菜单是二级菜单,那么
也应该把一级菜单显示出来。
接下来:查询当前用户的二级菜单 ,注意: 只找菜单,不需要left了,
因为只有url的才有id菜单,null的我们不需要,在这里
我们需要把当前登陆用户的一级菜单和二级菜单,再连一次菜单 ,
注意: 需要排序:把相同的一级菜单放在一起,根据父菜单的id为了方便映射

5.4 页面按钮的控制:

如果当前用户没有员工删除的权限,那么应该禁用该按钮,或者提示没有删除按钮的权限。
302是重定向
发送的异步ajax请求不可以显示一个Jsp页面,如果发送的是ajax请求,
那么就返回一个 json数据给我,如果我们发送的异步请求,而用户没有这个url的权限,我们的shiro
会拦截这个拦截,并且跳转到未授权的jsp页面,但是ajax请求是无法解析一个jsp页面的,让shiro
直接响应一个json格式的字符串,这个ajax请求解析这个json,弹出“对不起,你没有该权限。
如何实现?
要shiro区分请求是否是ajax请求
Index同步和 delete异步请求 中比较
写一个类继承PermissionsAuthorizationFilter,重写onAccessDenied方法
看请求头中是否有 X-Requested-With : XMLHttpRequested ,有就是ajax请求
httpServletRequest req = (HttpServletReqest)request
req.getHeader(“X-Requested-With)
判断X-Requested-With 并且有XMLHttpRequested.equals(header)
String json = “{”success”:false,”message”:”对不起,你没有这个权限”}”
把这个json写到响应里面去
respone.getWriter().write(json);
中文会乱码:来一个响应头 respone.setContentType(“text/json;charset=utf-8)
接下来需要配置,如果我们想要把自己写的过滤器,那么就需要注入到
ShrioFilterFactoyrBean中去, Filters: 为shiro配置自定义的过滤器
接下来需要使用它,以前使用的而是perms,现在需要用我们自己的,功能比较强大,
可以区分ajax请求
授权的过滤器是perms ,shiro里面已经写好了很多的过滤器
在哪里区分并且做出对应的响应
如果该用户没有这个权限,那么我可以把这个按钮不显示:
可以使用JSTL标签
指令 : taglib 引入
<shiro: hasPermission name = “dept:delete” / >就可以了

5.5 模型数据权限控制:


两个市场人员 A、B
A只能查询自己的客户
B只能查询自己的客户
但是对于超级管理员和市场部经理,可以查询所有的客户
通过sql 语句的生成:
在CustomerQuery对象中加两个字段
当前用户登陆的id
Boolean
adminOrManaer;
注意: 获取的时候
Id需要返回UserContext.getUser.getId();
adminOrManaer需要返回的是:
判断超级管理员和市场部经理是否等于getSn 是返回true
不是的话返回false;

5.6 JSON数据输出优化:


打开注解里面配置
Json属性设置 :
两个作用:
处理responseBody里面的日期类型 只是后台到前台有作用
处理前台到后台日期格式话的输入
必须保留
为null 字段不需要显示 他不会转json
	<mvc:annotation-driven>
<mvc:message-converters>
<!-- json属性设置 -->
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="com.fasterxml.jackson.databind.ObjectMapper">
<property name="dateFormat">
<!-- 处理responseBody 里面日期类型 -->
<bean class="java.text.SimpleDateFormat">
<constructor-arg type="java.lang.String" value="yyyy-MM-dd" />
</bean>
</property>
<property name="serializationInclusion">
<!-- 为null字段时不显示 -->
<value type="com.fasterxml.jackson.annotation.JsonInclude.Include">NON_NULL</value>
</property>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>

最后

以上就是大意眼睛为你收集整理的权限Shiro框架怎么在项目中使用?的全部内容,希望文章能够帮你解决权限Shiro框架怎么在项目中使用?所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(55)

评论列表共有 0 条评论

立即
投稿
返回
顶部