前言
参考百度上说的Apache Shiro是一个强大易用的java安全框架,提供了认证、授权、加密和会话管理功能,可以为任何应用提供安全保障,而其主要为解决以下四个问题:
1、 认证-用户身份识别,常被称为用户登录
2、 授权-访问控制
3、 密码加密-保护或隐藏数据防止被偷窥
4、 会话管理-每用户相关的时间敏感的状态
架构
以下是从其官网上截取的原理图
可以看出shiro的设计非常精妙,同时它不依赖于任何容器,即在java se和java ee中都可以使用,如果把shiro看做一个不透明的黑盒的话,即认证主体subject提供认证给security manager,其内部封装一些列细节方法去执行认证,这里的验证数据源可以是数据库的或者其他
下面将以用户的登录过程来模拟shiro的执行过程
身份认证流程
token令牌
这里该方法接收到前台传递过来的username和password信息,类比身份证,姓名是认证,但是身份证号码是作为认证的唯一凭证,只有身份证号码正确了,这个认证也就通过了,而这里的token可以理解为用户登录的令牌,里面记录着认证信息,然后交给shiro去验证
接下来就是执行登录动作了
SecurityUtils.setSecurityManager(securityManager); // 注入SecurityManager
Subject subject = SecurityUtils.getSubject(); // 获取Subject单例对象
subject.login(token); // 登陆
其中SecurityManager是一个单例对象,即全局变量,接着SecurityUtils会自动绑定当前线程,获得subject主体,关于subject可以这样理解其包含两个信息:
Principals: 身份,可以是用户名,邮件,手机号码等等,用来标识一个登陆主体身份;
Credentials: 凭证,常见有密码,数字证书等等;
最后就是登陆了,最后通过验证token是否合法返回不同结果
认证与授权
根据流程图,接下来security manager开始执行一系列的认证手段了,其中最主要的就是
AuthorizationInfo(角色权限认证),AuthenticationInfo(身份认证),可以简单这样理解,身份认证只是验证了这个subject的存在性,如果约定subject有某些权限,如管理员有删除或者访问某些url地址权限,而这个管理员就可以抽象为角色,也就是说权限是访问资源的权利集合,而角色是权限的集合
最后的realm域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色,权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源
一般情况下realm需要我们自定义去实现,因为shiro不知道哪些token是合法的
该realm类的结果就是根据token的合法性验证返回不同结果给相应的controller,目前只是从宏观上看了一个全过程,shiro是非常强大的,它的功能远不止如此
缓存机制
缓存的本质就是将原本只能存储在内存中的数据通过算法保存到硬盘上,再根据需求依次取出。可以把缓存理解为一个Map对象,通过put保存对象,再通过get取回对象。这里使用的是Ehcache缓存框架。具体代码如下:
其中
散列算法
通常情况下散列和加密本质上都是一样的,即将一个Object变成一串无意义的字符串,不同点是经过散列的对象无法复原,是一个单向的过程,而加密是可以双向的,即加密与解密,所以如果忘记密码,只能进行修改密码操作,下面是在项目中用到的散列算法
其中algorithmName为指定运用何种算法,hashIterations为散列次数,也就是数学中的迭代,将前一个结果作为参数在运算一次,salt盐可以理解为有了盐,并且每个盐唯一确定一个散列值,最后产生的newPassword是经过如下类
public SimpleHash(String algorithmName, Object source, Object salt, int hashIterations)
四个参数分别标识算法名称,散列对象,散列使用的salt值,散列次数。
匹配
匹配的功能就是用来匹配用户登录使用的令牌和数据库中保存的用户信息是否匹配。它的原始接口是CredentialsMatcher,一般情况下如果不自定义的话就会使用默认的实现类HashedCredentialsMatcher,如下是自定义的匹配
一般情况下,匹配的异常的结果都会抛出相应的异常,如 DisabledAccountException(禁用的帐号)、LockedAccountException(锁定的帐号)、UnknownAccountException(错误的帐号)、ExcessiveAttemptsException(登录失败次数过多)、IncorrectCredentialsException (错误的凭证)、ExpiredCredentialsException(过期的凭证)等
而针对获得realm数据源的情况,会设置五张表,分别是用户表(存储用户名,密码,盐等)、角色表(角色名称,相关描述等)、权限表(权限名称,相关描述等)、用户-角色对应中间表(以用户ID和角色ID作为联合主键)、角色-权限对应中间表(以角色ID和权限ID作为联合主键),其中用户与角色之前的关系为多对多,角色与权限之间的关系也是多对多
会话
用户的一次登录即为一次会话,即session,Shiro也可以代替Tomcat等容器管理会话。而针对会话,可以处理的情况太多了,如记录用户信息和行为等等,比如保存用户信息
TUserEntity user=tUserService.queryObject(username);
subject.getSession().setAttribute(“user”, user);
ssm+shiro集成
web.xml中的配置
其中主要关心的是web容器将将Shiro的配置文件交给Spring监听器初始化以及配置了shiro的过滤等
这里shiro的配置都在spring-shiro.xml中配置
|
|
其中最主要的是filterChainDefinitions,这里声明了权限控制用户访问哪些url,而且访问是有顺序的,即执行了前者后者将不再执行,其中anon为匿名访问,authc为需要身份认证通过才可以访问,这里的内容较多,具体参考官方文档
最后只要通过前台页面提交数据,经过一系列流程,最终就可以完成权限控制了,事实上shiro的内容很多,而且很丰富,只有不断在实践中踩坑,学习,总结才能更好的认识和运用它