Shiro中的 Realm使用详解

前言
之前写项目用了 Shiro 框架,来进行安全验证以及权限管理。当时项目赶得急,没怎么深入了解,只能说能跑能改,不过在使用的过程中发现 Shiro 确实很优秀。现在回过头来学习原理,读读源码,深入的学习下。·

本篇博文主要写的是关于使用 Shiro 起步时最重要的一块,找了一些资料,力求写得简单明了。

简介
Realm:域,Realm 充当了 Shiro 与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro 会从应用配置的 Realm 中查找用户及其权限信息。从这个意义上讲,Realm 实质上是一个安全相关的 DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给 Shiro 。当配置 Shiro时,你必须至少指定一个 Realm ,用于认证和(或)授权。配置多个 Realm 是可以的,但是至少需要一个。
Shiro 内置了可以连接大量安全数据源(又名目录)的 Realm,如 LDAP、关系数据库(JDBC)、类似 INI 的文本配置资源以及属性文件等。如果缺省的 Realm 不能满足需求,你还可以插入代表自定义数据源的自己的 Realm 实现。

功能
Realm能做的工作主要有以下几个方面:

身份验证(getAuthenticationInfo 方法)验证账户和密码,并返回相关信息

权限获取(getAuthorizationInfo 方法) 获取指定身份的权限,并返回相关信息

令牌支持(supports方法)判断该令牌(Token)是否被支持

令牌有很多种类型,例如:HostAuthenticationToken(主机验证令牌),UsernamePasswordToken(账户密码验证令牌)

这里主来说明一下关于前两点验证方面的逻辑,因为令牌一般用的都是 UsernamePasswordToken,哪怕用 HostAuthenticationToken,也没必要细讲,这个函数很少用到。

身份验证
我们看到第一个方法就是我们上面说的“验证账户和密码,并返回相关信息”的方法。从方法的名字上看,只有取得验证信息的意思,其实这里面还包括了进行验证的逻辑。
看Javadoc,这个方法的作用是:根据传进来的 Token,返回用户的验证信息。下面说明一下 Token 和 用户验证信息 。

Token:就是要拿来进行验证的信息,例如:如果是 UsernamePasswordToken 的话,这个 Token 的内容就是“用户提交的用户名和密码”。

来看下 UsernamePasswordToken 的属性。

用户验证信息:就是用户验证通过后,返回给系统的信息。例如:用户登录验证的话,一般来说,返回给系统的“用户验证信息”就应该是这个用户的“用户名和密码”。但也可以返回其它信息,例如返回用户的“邮箱地址和登录密码”信息,做为“用户验证信息”。 那么返回给谁呢,Shiro 中的三大组件之一的 Subject。

不细谈,这么说吧,Subject:即“当前操作用户”。但是,在 Shiro 中,Subject 这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。但考虑到大多数目的和用途,你可以把它认为是 Shiro 的“用户”概念。

上面说了“根据传进来的Token”和“返回用户的验证信息”,但没有说验证的过程,这个过程也是在这个方法中进行。我们看一下源码:

权限获取
“权限验证”的处理,是由接口定义的。但“验证是否有访问权限”的逻辑,则是由类定义的。定义的类为:AuthorizingRealm ,在这个类中有个getAuthorizationInfo 方法。这个方法和getAuthenticationInfo 方法的处理流程有点像:

验证是否有指定的权限

返回用户的权限信息

调用时机
下面看一个实际登录的 Controller 的例子:

不过,getAuthorizationInfo 的执行调用方式包括上面的总共有三个:

subject.hasRole(“admin”) 或 subject.isPermitted(“admin”):自己去调用这个是否有什么角色或者是否有什么权限的时候;
@RequiresRoles(“admin”) :在方法上加注解的时候;
[@shiro.hasPermission name = “admin”][/@shiro.hasPermission]:在页面上加shiro标签的时候,即进这个页面的时候扫描到有这个标签的时候。
实现
需要注意的是,在 Shiro 实际使用中,我们是肯定会自定义一个 Realm 类的。

从上面的功能说明可以看出来,在权限控制中比较重要的验证(登录或权限)逻辑,都是在Realm中做的。Realm的类继承如下:

不同的继承,需要实现不同的方法。继承了 AuthorizingRealm 的类,都要实现上面说的 getAuthenticationInfo 和 getAuthorizationInfo 方法,来完成身份验证和权限获取。但如果自定义的 Realm 类只实现 Realm 接口的话,只需要 getAuthenticationInfo 方法就可以。下面看一个只实现 Realm 接口的自定义 Realm:

但是在使用中基本上都会对账户进行权限管理,下面看一个继承 AuthorizingRealm 的自定义 Realm:

转自:https://blog.csdn.net/zx48822821/article/details/80503742

发表回复