用于前后端分离情况,需要使用token进行权限验证
前后端分离——使用token完成Shrio鉴权认证
○核心流程
- 用户登录,保存token到数据库,并返回给前端
- 用户访问资源并携带token,经过各种过滤器
- 因为没有执行过
Subject.login()
所以访问限制资源是会被拦截失效- 失败后调用自定义
Filter
的onAccessDenied()
,获取携带的token并执行登录(executeLogin)- 登陆时使用自定义的
Realm
验证token合法性和时效性,通过则返回认证信息- Shiro调用
CredentialsMatcher
验证输入的credentials与Realm中返回的认证信息是否匹配(需要自定义Mathcer)- 有了认证信息即可进行授权鉴权!!!
○原理解析
使用token进行登录认证,主要就是要求前端的请求需要合法token支持,所以这个token是前后端共享的,因此需要JWT
进行加密,而设计Shiro认证时需要考虑到认证信息由默认的Username/Password
转变成了自定义的Token
,因此不能再使用原有的过滤器来控制认证鉴权,所以实现一个Filter是完成这个任务的一个至关重要的操作。
○自定义Filter实现原理
以不需要RememberMe为例,我们需要实现的 Filter Interface 为AuthenticatingFilter
,实现几个关键的方法:
-
AuthenticationToken createToken(request,response)
这个方法将会在认证失败后尝试登录时调用(executeLogin),它返回的AuthenticationToken将作为
Subject.login
方法的参数,也就是**它将进入到我们自定义的Realm当中!**根据需求,此处创建AuthenticationToken 我们需要依赖于前端传递的token,因此我们是从request中获得的(请求头、请求体)无法获取怎么办呢?直接返回null即可,Shiro将会抛出
IllegalStateException
。 -
boolean onAccessDenied(request,response)
在请求被Filter验证失败时会调用此方法,该方法的返回值决定这个请求是否能够放行,在这个方法中我们才会执行登录操作!我们根据登录是否成功(Realm中返回认证信息)来决定是否放行,如何登录?就采用刚才所说的
executeLogin
方法,这是AuthenticatingFilter
类已经实现了的方法,根据createToken返回的Token进行登录,如果登录成功即可返回true
○自定义Realm实现原理
使用Token方法进行验证的Realm其实与Username/Password的核心思想是相同的,只不过认证时通过前端的token从数据库中取出完整的token实体,对token本身的信息进行校验如是否失效等作为认证是否通过的依据。
授权时,我们需要从Token实体中获取到用户对应的ID,通过ID从数据库中查找角色、权限进行然后正常的进行授权操作!
○自定义Token
这里要说的Token分为:
前端能够获取到的token——
String
这个理应为一个加密后的字符串,也是认证流程中的核心。
Shiro进行认证的token——
AuthenticationToken
实际上就是把String类型的token封装成实现接口的对象,其token作为
Principal
也作为Credentials
保存于数据库中的token——
JavaBean
一个实体Entity类型的对象,与数据库设计有关,加密过的token应是其主要部分,此外,该token对应的用户与之是一对一关系,所以也可以保存对应用户的
ID
理清了各种Token,接下来要解决的就是Token如何加密的问题了,就如前面提到的,Token可以使用JWT
,使用JWT可以方便的设置失效时间,节省数据库资源,也提供secret加密,能够进行二次验证,这里不再赘述使用方法。
○自定义CredentialsMatcher
@Override
public boolean doCredentialsMatch(AuthenticationToken authenticationToken, AuthenticationInfo authenticationInfo) {}
Token是从前端获取的Token,Info是Realm返回的Info,在该方法中实现验证即可。
😄自定义Matcher后需要注入到自定义的Realm中,通过
setCredentialsMatcher
方法