好久没写博客了,这段时间对最近项目做个总结,先从登入下手,话不多说直奔主题,Shiro的登录使用以及原理。
目录
一、Shiro主要作用
shiro主要的作用就是实现用户登录(认证,授权,加密等),用户登录后的用户信息存储(缓存),用户登出等。
二、登录的使用
在使用登录的时候,最常见的一串代码就是通过工具类SecurityUtils获取Subject,然后对Token进行login();
// 得到subject然后对创建用户名/密码身份验证
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("hu", "123");
subject.login(token);
这时候只对这串代码进行编译运行,你会发现会报一个异常信息
org.apache.shiro.UnavailableSecurityManagerException: No SecurityManager accessible to the calling code, either bound to the org.apache.shiro.util.ThreadContext or as a vm static singleton. This is an invalid application configuration.
2.1 SecurityManager的生成与使用
根据报错信息以及对SecuriTyUtils的源码发现使用SecurityUtils.getSubject()的时候必须要为其设置一个securityManager,具体如下:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.apache.shiro;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.subject.Subject.Builder;
import org.apache.shiro.util.ThreadContext;
public abstract class SecurityUtils {
private static SecurityManager securityManager;
public SecurityUtils() {
}
public static Subject getSubject() {
// 通过ThreadContext获取对应的Subject,若未在ThredContext中加入该subject必定为空
// ThreadContext可以通过源码了解到为使用过TreadLocal模式 具体看标题三
//因为是TreadLocal所以表示每个线程初次进来的时候,获取到的subeject必为空
Subject subject = ThreadContext.getSubject();
if (subject == null) {
//具体看下列代码块 主要执行为通过SecurityManager创建出Subject
subject = (new Builder()).buildSubject();
ThreadContext.bind(subject);
}
return subject;
}
public static void setSecurityManager(SecurityManager securityManager) {
SecurityUtils.securityManager = securityManager;
}
public static SecurityManager getSecurityManager() throws UnavailableSecurityManagerException {
SecurityManager securityManager = ThreadContext.getSecurityManager();
if (securityManager == null) {
securityManager = SecurityUtils.securityManager;
}
if (securityManager == null) {
String msg = "No SecurityManager accessible to the calling code, either bound to the " + ThreadContext.class.getName() + " or as a vm static singleton. This is an invalid application " + "configuration.";
throw new UnavailableSecurityManagerException(msg);
} else {
return securityManager;
}
}
}
// 在Subjct初次获取到为空的时候会调用的Subject的静态内部类,创建一个Builder,在通过buildSubject的方法进行实现Subject的生成
public static class Builder {
private final SubjectContext subjectContext;
private final SecurityManager securityManager;
// 需要先设置对应的SecurityManage
public Builder() {
this(SecurityUtils.getSecurityManager());
}
// 通过securityManager创建出subject
public Subject buildSubject() {
return this.securityManager.createSubject(this.subjectContext);
}
..........loading...............
}
得出结论 Subject的实例都会(也是必须)绑定一个SecurityManager,对Subject的操作会转为Subject与SecurityManager之间的交互。
看来Subject的生成都是SecurityManager在做苦力活啊。
那么SecurityManager是怎么生成的?
先查阅下官方文档SecurityManager是怎么生成的
根据官方文档:http://greycode.github.io/shiro/doc/tutorial.html
那么我们就先通过使用ini文件进行尝试下:
在resource下创建一个shiro.ini文件放入用户信息
[users]
hu=123
然后通过官方给出的:
//1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
Factory<SecurityManager> factory =
new IniSecurityManagerFactory("classpath:shiro.ini");
//2、得到SecurityManager实例 并绑定给SecurityUtils
SecurityManager securityManager = factory.getInstance();