mac_girl

使用shiro做权限管理的学习笔记整理

Shiro权限管理

参考:https://www.cnblogs.com/jpfss/p/8352031.html

Shiro解决的问题

授权和鉴别的问题:Authenrization(授权) Authentication(证明)

关键对象

Subject:主体

访问系统的用户,可以是用户、程序等

Principal:身份信息

主体(subject)进行身份认证的标识 ,具有唯一性。如:用户名、手机号、邮箱地址等

credential:凭证信息

只有主体自己知道的安全信息。如:密码、证书等

授权

主体 ------ 》身份认证------- 》分配权限 ------ 》访问系统的资源

授权操作

who: 主体是什么

what:主体要操作什么资源

how: 主体对资源进行什么操作

总结:who 对 what 进行 how操作

权限的分类

  1. 粗颗粒
    对资源类型的权限
  2. 细颗粒
    对资源实例的权限

权限模型

用户 (账号,密码)

角色(角色名称,角色id)

权限(权限名称,资源名称,资源url)

用户与角色关系

角色与权限关系

权限分配

  1. 主体只允许在权限范围内对资源进行操作
  2. 权限分配的数据通常需要持久化 ,根据上边的数据模型创建表并将用户的权限信息存储在数据库中

基于角色的访问控制

是以角色为中心进行访问控制

主体.hasRole("总经理角色id")

如:主体的角色为总经理

    总经理可以查询企业运营报表,查询员工工资信息

    判断主体的角色 = 总经理: ----->查询工资

     现在我给部门经理也开放了查询工资的权限,需要更该代码,判断如果角色是部门经理,也可以进行查询操         作,因为需要更改代码,系统的可用性差。

主体.hasRole("总经理角色id") || 主体.hasRole("部门经理角色id")

基于资源的访问控制

是以资源为中心进行访问控制

如:主体.hasPermission("查询工资权限标识")

粗颗粒度

粗颗粒度:对资源类型的管理,控制到菜单、按钮、方法

例如:用户具有用户管理的权限,具有导出订单明细的权限

对系统功能操作使用统一的粗颗粒度的权限管理

细颗粒度

细颗粒度:对资源实例的控制 ,控制到数据级别的权限

例如:用户只允许修改本部门的员工信息,用户只允许导出自己创建的订单明细

基于url拦截的实现

原理: 将系统操作的每个url配置在权限表中,将权限对应到角色,将角色分配给用户,用户访问系统功能通过Filter进行过虑,过虑器获取到用户访问的url,只要访问的url是用户分配角色中的url则放行继续访问。

1.用户访问系统的资源 ------ 》经过身份拦截器-------》判断用户访问的资源url是否是公共资源-------》如果是,则予以放行 ------》如果不是 ------- 》对用户的身份进行验证-------》判断用户是否有session-------->有------>进入权限拦截器-------》没有,跳转登录页面,并将用户的账号,密码以及权限放在session中 ------ 》重新访问系统资源 ------- 》经过权限拦截器 ------->获取用户的资源url判断是否是公共资源 ------ 》如果是,直接访问 ------ 》如果不是,根据用户session中的权限,判断用户是否拥有访问该资源url的权限 ------ 》如果没有 ------->返回拒绝页面

用户登录(将用户的账号,密码,以及包含的而所有资源url放在session中)

身份认证拦截器(访问资源时判断是否访问公共资源,如如不是,则进行身份认证,即判断sessison是否存在)

权限认证拦截器(当用户通过身份认证后,再判断用户是否有访问该资源url的权限)

身份认证拦截器

Implement HandlerIntrceptor类

重写HandlerIntrceptor的PreHandle(request,resonse,Object handler)方法

使用权限框架的好处

1.节省系统开发时间

2.提供了完善的认证和授权功能

shiro的介绍

shiro:

  1. 将软件系统的安全认证相关的功能抽取出来
  2. 实现用户身份认证,权限授权、加密、会话管理等功能
  3. 是一个通用的安全认证框架

shiro就可以非常快速的完成认证、授权等功能

Shiro的架构

subject :

  1. subject记录了当前操作用户 ,可能是一个通过浏览器请求的用户,也可能是一个运行的程序
  2. subject是shiro的一个接口,定义了很多认证授相关的方法
  3. 外部程序通过subject进行认证授,而subject是通过SecurityManager安全管理器进行认证授权

SecurityManager :安全管理器

  1. 对全部的subject进行安全管理,它是shiro的核心
  2. 通过SecurityManager可以完成subject的认证、授权
  3. SecurityManager是通过Authenticator进行认证,通过Authorizer进行授权,通过SessionManager进行会话管理

Authenticator :认证器

  1. Authenticator是一个接口 ,shiro提供ModularRealmAuthenticator实现类

Authorizer :授权器

  1. 认证器认证通过 ,通过授权器判断用户是否有此功能的操作权限

realm :获取用户权限数据

  1. 比如:如果用户身份数据在数据库那么realm就需要从数据库获取用户身份信息。
  2. 在realm中还有认证授权校验的相关的代码

sessionManager :会话管理

  1. 它不依赖web容器的session ,实现单点登录

SessionDAO :会话dao

  1. 对session会话操作的一套接口
  2. 如要将session存储到数据库,可以通过jdbc将会话存储到数据库

CacheManager :缓存管理

  1. 将用户权限数据存储在缓存

Cryptography :密码管理

  1. shiro提供了一套加密/解密的组件
  2. 比如提供常用的散列、加/解密等功能

Shiro的使用

引入jar包

shiro-core:核心包

shiro-web:与web整合

shiro-spring :与spring整合

shiro-ehcache :

shiro-quartz :任务调度quartz整合

注:可使用shiro-all 导入全部的包

引入shiro.ini文件

shiro的认证流程

securitymanger(构建securitymanger环境)--------》subject.login()(提交认证) ----------> securitymanger.login() (执行认证) --------》Authenticator (执行人认证) -----》Realm(根据身份获取验证消息)

shiro项目的搭建

(构建securitymanger对象)

  1. 创建factory 关联shiro配置文件 ------>通过工厂创建securitymanger ------》将securitymanger运行到环境中
    ------- 》 创建subject对象

    subject.login()(提交认证)

  2. 生成用户的token令牌 ------- 》将用户的令牌放在subject.login(token)中

执行认证,判断用户的身份

subject.isAuthenticated()

Authenticator(subject.isAuthenticated())的实现 :

  1. ModularRealmAuthenticator调用realm从ini配置文件取用户真实的账号和密码 ,这里使用的是IniRealm(shiro自带)
  2. IniRealm先根据token中的账号去ini中找该账号,如果找不到则给ModularRealmAuthenticator返回null,如果找到则匹配密码,匹配密码成功则认证通过

自定义Realm

  1. Shiro自带的IniRealm,是从ini配置文件中读取用户的信息
  2. 从系统的数据库中读取用户信息,所以需要自定义realm
  3. 自定义的realm继承AuthorizingRealm。(授权)
    AuthorizingRealm的方法:
    • boolean support(Authentication Token) // 支持UserPaswwordToken

    • AuthenticationInfo doGetAuhenticationInfo(AuthenticationToken Token) //认证
      doGetAuthenticationInfo中方法的实现:
      获取Token的username数据,--------》 拿token的username到数据库中去比对,-----》比对成功在从数据库中取出password与token的password比对---------》返回验证信息,由父类返回AuthenticationInfo------>SimpleAuthenticationInfo(username,password,getName())

    • Authorization doGetAuthorizationInfo(principalCollection pricipal )//授权

    • String getName()
      String getName(){
      return "customRealm1";
      }

自定义Realm的shiro.ini的配置

shiro-realm.ini文件

[main]

#自定义 realm,自定义的realm的类的路径

customRealm=cn.itcast.shiro.authentication.realm.CustomRealm1 

#将realm设置到securityManager

securityManager.realms=$customRealm

散列算法

作用:生成一段文本的摘要信息

特点:不可逆,将内容可以生成摘要,无法将摘要转成原始内容

用途:常用于对密码进行散列

常用的散列算法:MD5、SHA

散列算法的实现:原始数据+salt(盐:即一个随机数) -------- 》生成一个散列值

例:11111(原始数据)+ salt(随机数) ---------》96e79218965eb72c92a549dd5a330112 (散列值)

使用 new Md5Hash()实现散列:

String hh = new Md5Hash("11111").toString(): 不加盐散列

String hh = new Md5Hash("1111","eteokeus",1.toString()):加盐散列

使用SimpleHash散列:

String hh = new SimpleHash("MD5","11111","eteokeus",1).toString()

散列算法在Realm的使用

将盐和散列后的值存在数据库中 ,自动从数据库取出盐和加密后的值,由shiro完成密码校验

增加散列算法后 shiro.ini文件的配置

shiro-cryptography.ini

shiro的授权方式

编程式:通过写if/else 授权代码块完成

Subject subject = SecurityUtils.getSubject();

if(subject.hasRole(“admin”)) {

//有权限

} else {

//无权限

}

注解式:通过在执行的Java方法上放置相应的注解完成

@RequiresRoles("admin")

public void hello() {

//有权限

}

JSP/GSP 标签:在JSP/GSP 页面通过相应的标签完成

<shiro:hasRole name="admin">

<!— 有权限—>

</shiro:hasRole>

第一种:编程式授权方式

shiro配置文件:shiro-permission.ini

用户的配置规则:用户=密码,角色1,角色2,....

角色的配置规则:角色=权限1,权限2,....

权限的配置规则:资源标识符:操作:资源实例标识符

例:user(资源标识符):update:001 :修改表user实例001的权限

    user:*:001:操作001的所有权限

基于角色授权

判断用户是否有某一角色:subject.hasRole("role1")

判断用户是否有多个角色:subject.hasAllRoles(Arrays.list("roles1","roles2"))

检查权限,判断是否授权成功:checkRole("roles1") , checkRoles("roles1","roles2")

基于资源授权

判断用户是否拥有某一权限:subject.isPermitted("user:create")

判断用户是否拥有多个权限:subject.idPermittedAll("user:create","user:delete:1")

检查权限,判断是否授权成功:subject.permission("user:create"),subject.perssmions("user:create","user:delete:1")

自定义Realm,实现资源的授权

完善自定义类的AuthorizationInfo()方法

根据用户身份信息从数据库查询权限字符串,由shiro进行授权

AuthorizationInfo()方法的实现

AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals)

  1. 从Principal中获取用户的身份信息
    String username = (String)principals.getPrimaryPrincipal()
  2. 根据用户信息到数据库查询用户的权限
  3. 将用户的所有权限放在一个AuthorizationInfo中,返回一个SimpleAuthorization对象
    return new SimpleAuthorizationInfo().addPermission("权限名称")

用户授权:

subject.isPermitted("user:delete")

授权流程:

执行subject.isPermitted("user:delete") -------- >通过ModularRealmAuthorizer进行授权 --------->调用realm获取权限信息 ------ >通过permissionResolver解析权限字符串,校验是否匹配

shiro与spring web项目的整合

1.取消原springmvc认证和授权拦截器

去掉springmvc.xml中配置的LoginInterceptor和PermissionInterceptor拦截器

2.加入shiro的jar包

shiro - spring

shiro - web

3.Web.xml中添加shiro filter

3.配置applicationContext-shiro.xml

securityManager:这个属性是必须的。

loginUrl:没有登录认证的用户请求将跳转到此地址进行认证,不是必须的属性,不输入地址的话会自动寻找项目web项目的根目录下的”/login.jsp”页面。

unauthorizedUrl:没有权限默认跳转的页面。

shiro在认证过程中发生错误后将异常类的路径通过request返回

session由shiro管理,需要修改首页的controller方法,将session中的数据通过model传到页面

获取用户权限对象

List permissions = SysService.findSysPermissionList(usrename);

permissions[0].getPercode(): 获取权限内容

  1. 对controller开启AOP
    在springmvc.xml中配置shiro注解支持,可在controller方法中使用shiro注解配置权限

5.权限注解控制@RequiresPermissions ("资源权限")

必须拥有“item:query”权限方可执行该方法

shiro与Ehcache整合

shiro每次授权都会通过realm获取权限信息,为了提高访问速度需要添加缓存,第一次从realm中读取权限数据,之后不再读取

1.添加Ehcache jar包

ehcache-core.jar

shiro - ehcache.jar

  1. 在pplicationContext-shiro.xml中配置缓存管理器

3.配置shiro-ehcache.xml

清空缓存

claerCache(principals)

当用户权限修改后,用户再次登陆shiro会自动调用realm从数据库获取权限数据,如果在修改权限后想立即清除缓存则可以调用realm的clearCache方法清除缓存。

realm中定义clearCached方法:

Session管理

在校验账号之前校验验证码

写一个类 extend FormAuthenticationFilter

在boolean onAccessDenied()中进行验证操作

FormAuthenticationFilter配置

修改applicationContext-shiro.xml中对FormAuthenticationFilter的配置。

在shiroFilter中添加filters:

formAuthenticationFilter定义

自动登录

用户登陆选择“自动登陆”本次登陆成功会向cookie写身份信息,下次登陆从cookie中取出身份信息实现自动登陆

1.用户身份实现java.io.Serializable接口

2.配置rememberMeManager

3.FormAuthenticationFilter配置

修改formAuthenticationFitler添加页面中“记住我checkbox”的input名称

主体进行身份验证后需要分配权限才能访问资源

使用springmvc实现身份验证拦截和权限分配拦截

身份验证拦截和权限拦截的实现

extend HandelerInteceptor 实现preHandle()方法-------》在该方法里判断访问的是否是公有资源-------》是,则予以访问------》不是 则判断是否登录,即session是否有数据 ------>没有,跳转到登录页面 ------>有 ------》到达权限认证过滤器--------》判断用户访问的是否是公有资源 -----》是,直接访问-------》不是,判断是否是经过身份验证就可以访问的资源------->不是,根据用户的id获取用户的所有权限------》判断用户访问的资源url是否在用户的权限里

登录时对用户的账号密码进行认证

首先获取session中的验证码,判断验证码是否相等,------》根据用户的账号查询用户的信息 判断用户是否存在 ------》进而查询用户的权限信息,菜单信息 ------》将用户的username,password,权限菜单、权限url等记入activeUser类,并写入session

使用shiro实现身份验证拦截和权限分配拦截

将用户名和密码配置在shiro.ini文件中,从配置文件中读取用户信息

关联shiro.ini文件,创建Sercuritymanger工厂 ----- 》从工厂中创建一个securitymanger ------>将securitymanger运行到环境中 ------》创建subject --------》设置用户登录的Token(username,password) ------- >拿到用户的token ------- >subject.login(token) ------->使用subject.isAuthenticated()判断用户是否存在,底层调用realm从ini配置文件取用户真实的账号和密码 , IniRealm先根据token中的账号去ini中找该账号,如果找不到则给ModularRealmAuthenticator返回null,如果找到则匹配密码,匹配密码成功则认证通过。

系统的数据库中读取用户信息

获取认证信息:

Sysuer sysuer = SysService.findSysuserByUsercode("usercode") 😕/根据用户的账号获取用户的信息

判断用户是否存在 sysuer == null ?

根据用户id取出菜单

List perssions = sysService.findMenuList(usserid);

构建主体信息ActiveUser,将主体信息放在该对象中

系统给用户授权:

根据用户的id获取用户的所有权限

List perssions = sysService.findSysPermissionList<>

jj

posted on 2019-08-21 19:22  宇宙美少女  阅读(567)  评论(0编辑  收藏  举报

导航