功能: 认证,授权,加密,会话管理,,缓存。。。。
我的理解:什么是shiro,它就是一个基于cookie和session会话技术,采用mvc思想来完成用户的登陆注册和应用资源权限管理的安全框架。它的mvc三层模型分别是jsp/html 【v视图层】 realm【m模型层】 subject+ securityManager【门面+管理=c=(控制层+业务层)】
shiro是一个安全框架。在java ee的mvc三层模型中,每一层它都可以发挥作用
在controller层:shiro创建了一个UsernamePasswordToken对象。用来存储用户的姓名,密码,ip主机地址,Boolean类型的(是否让网站记住我—即是否回传token到客户端的cookie里保存)
subject门面之意,相当于mvc的表现层(接收用户传来的参数,封装成UsernamePasswordToken传给服务层securityManager),服务层是securityManager,它又是一个接口主要由DefaultSecurityManager 实现该接口(里面的业务是:是否授权,是否认证),数据持久层dao是realm,它负责存取用户名,角色,权限。
架构图:
authentication 认证(登录) authorization 授权(对页面进行操作时shiro会判断你有无相关的操作权限) session(javaEE和javaSE都可以使用会话) cryptography 盐加密 concurrency 多线程应用的并发验证
运行流程:
web application=============>subject(门面) ===============>securityManager(核心管家) ========>Realm(数据源,从数据库的用户,角色,权限表中取得数据,相当于dao层)
shiro认证(登录)过程:
查找接口的实现类:
IDEA 风格 ctrl + alt +B
查看类或接口的继承关系:
ctrl + h
1.获取当前的 Subject. 调用 SecurityUtils.getSubject()
2.测试当前的用户是否已经被认证(登陆).调用 Subject 的 isAuthenticated()
3.若没有被认证,则把用户名和密码封装为 UsernamePasswordToken 对象
1).创建一个表单页面
2).把请求提交到 SpringMVC 的 Handler
3).获取用户名和密码
4.执行登陆: 调用 Subject 的 login(AuthenticationToken) 方法【AuthenticationToken是接口,UsernamePasswordToken是该接口的实现类】
5.自定义 Realm 的方法, 从数据库中获取对应的记录,返回给 Shiro. 【仅仅是认证的话,继承AuthenticatingRealm类即可以了,但如果是授权,还是要实现Realm接口才行】
1).实际上需要继承org.apache.shiro.realm.AuthenticatingRealm 类
2).实现doGetAuthenticationInfo(AuthenticationToken) 方法
6.由 shiro 完成密码的对比
1).通过AuthenticatingRealm 的 credentialsMatcher 属性来进行的密码的比对
2).把一个字符串加密为MD5,盐值加密
2.1).在 doGetAuthenticationInfo 方法返回值创建SimpleAuthenticationInfo 对象的时候,需要使用
SimpleAuthenticationInfo(principal,credentials,credentialsSalt,realmName)构造器
2.2).使用 ByteSource.Util.bytes()来计算盐值.
2.3).盐值需要唯一:一般使用随机字符串或user id .
2.4).使用new SimpleHash(hashAlgorithnName,credentials,salt,hashIterations)来计算盐值加密后的密码的值
授权:
admin用户可访问admin.jsp 和 user.jsp页面, user 用户只能访问 user.jsp页面,密码都为123456
1.授权需要继承AutohorizingRealm 类,并实现其 doGetAuthenticationInfo 方法
2.AuthorizingRealm 类继承自 AuthenticatingRealm 但没有实现AuthenticatingRealm 中的
doGetAuthenticationInfo 所以认证和授权只需要继承AuthenticatingRealm 就可以了,同时实现它的两个抽象方法
权限注解:
https://blog.csdn.net/acmman/article/details/78765315
shiro标签使用方法:
https://blog.csdn.net/yaodieteng1510/article/details/79992247
代码分析:
SecurityUtils.getSubject();得到subject(接口)
org.apache.shiro.subject.support.DelegatingSubject实现了subject接口
subject.login( UsernamePasswordToken passwordToken ) 而
UsernamePasswordToken passwordToken是
AuthenticationToken token接口的实现类
实际是DelegatingSubject.login()============subject门面之意,相当于mvc的表现层(接收用户传来的参数,封装成UsernamePasswordToken传给服务层securityManager),服务层是securityManager,它又是一个接口主要由DefaultSecurityManager 实现该接口(里面的业务是:是否授权,是否认证),数据持久层dao是realm,它负责存取用户名,角色,权限。
DefaultSecurityManager extends SessionsSecurityManager #组合SubjectDAO、SubjectFactory主要是创建createSubject、login、logout.
SessionsSecurityManager extends AuthorizingSecurityManager #实现Session的创建Start和getSession,并清空sessionManager
AuthorizingSecurityManager extends AuthenticatingSecurityManager #组合authorizer权限验证哭器,并清空authorizer
AuthenticatingSecurityManager extends RealmSecurityManager #组合authenticator身份验证器,并清空authenticator
RealmSecurityManager extends CachingSecurityManager #RealmSecurityManager 管理realams,并清空Cachemager
CachingSecurityManager implements SecurityManager, Destroyable, CacheManagerAware, EventBusAware #CachingSecurityManager 注入Cachemager,并清空Cachemager
DefaultSecurityManager通过继承。。。。从而实现securityManager接口。DefaultSecurityManager的login方法
public Subject login(Subject subject, AuthenticationToken token)
AuthenticationInfo info = authenticate(token); //调用了授权器,而AuthenticationInfo是一个接口,它的实现类是
AbstractAuthenticator,
public abstract class AbstractAuthenticator implements Authenticator, LogoutAware
关于realm的类:
public class ModularRealmAuthenticator extends AbstractAuthenticator {
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken){
Collection<Realm> realms = getRealms();
}
protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, AuthenticationToken token) {
AuthenticationInfo info = realm.getAuthenticationInfo(token);
}
}
走到下一个Realm的一个实现类:
public abstract class CachingRealm implements Realm{}
public abstract class AuthenticatingRealm extends CachingRealm implements Initializable{
public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
AuthenticationInfo info = getCachedAuthenticationInfo(token);
if (info == null) {
//otherwise not cached, perform the lookup:
/**注意====================================================>
*doGetAuthenticationInfo就是我们要继承的org.apache.shiro.realm.AuthenticatingRealm 类,并且要实现的doGetAuthenticationInfo(AuthenticationToken) 方法
*/
info = doGetAuthenticationInfo(token);
}