深度剖析spring+shiro认证机制

引言

项目中使用了shiro作为用户认证、角色管理、权限管理等,使用起来还是特别方便的,开发者只需要SecurityUtils.getSubject()获取subject就可以实现登录,以及权限验证。这样大大简化了开发者的功能,但是也有点让开发者感觉好奇,shiro是如何做到的呢。

本章将会对shiro的认证机制进行深入剖析,由于从官方文档以及其他的一些博客对shiro的使用都做了详细的说明,所以具体的shiro的使用就不在做累述。从官网可以了解到,在使用shiro的时候开发者只需要和subject交互就可以实现登录,以及相关的验证过滤了,那么shiro底层需要如何实现才能满足这种需求呢,本节将对subject验证的过程进行深入剖析。

SecurityUtils深度分析

从shiro的实用案例中,我们可以看出开发者只需要通过SecurityUtils.getSubject()方法获取到subject,然后通过subject就可以实现用户的login、logout、isAuthenticated等功能,那么不同的请求时调用的SecurityUtils.getSubject()是如何保证获取到是请求对应的用户呢?这就需要我们对subject的来源进行一个详细的分析!

首先通过分析SecurityUtils.getSubject()发现,该函数从线程的ThreadLocal<Map>中获取到的subject,这个说明subject来自于web的处理线程,而且对于的key是一个常量值,但是在web服务器中一个线程可能会在不同时刻处理不同的用户,那么在使用同一个key的时候如何保证获取的是当前请求的用户的subject呢?

通过结合web服务器的线程模型、session机制,整理出了spring中shiro的一个认证的流程,大致处理过程如下,各个机制的介绍后面会进行详细的分析:

AbstractShiroFilter的doFilterInternal方法:会为每一个request创建一个subject(粗略的步骤是:首先提取session,然后判断session中是否存在,如果存在那么从session中提取用户登录信息放入到新建的subject),并把该subject放入当前线程的ThreadLocal<Map>中。然后当前线程继续调用其他的filter,最后调用应用层的rest接口函数,然后rest接口函数就可以通过SecurityUtils.getSubject()方法从当前线程中的ThreadLocal<Map>中获取subject了。

具体实现可以参考:
DefaultSubjectContext: resolvePrincipals()
AbstractShiroFilter:doFilterInternal()

session机制

由于http是无状态的,所以在web项目中大多使用session来标识一个客户端,shiro和web的集成也是建立在该机制之上的。

1、当服务器接受到客户端请求的时候,首先会查找cookie是否存在,如果存在那么继续判断cookie中是否存在sessionId参数;如果不存在那么会分析url中是否有sessionId参数;如果有再判断用户session是否超时,如果都不存在或者是超时,那么会重新创建一个session并把sessionId写入response中,并返回给客户端。

2、客户端在收到response之后会判断客户端是否支持cookie机制,如果不支持那么客户端应该将sessionId存放在客户端的缓存中,每一个请求都作为url的参数放在url中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章