一.最基本的使用

1.Maven依赖

        <dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.2.4</version></dependency><dependency>  <groupId>org.slf4j</groupId>  <artifactId>slf4j-api</artifactId>  <version>1.7.13</version>  </dependency>  <dependency>  <groupId>org.slf4j</groupId>  <artifactId>slf4j-log4j12</artifactId>  <version>1.7.13</version>  </dependency>

2.配置文件

[users]
user1 = http://blog.csdn.net/unix21
admin1 = 11111

3.调用代码

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class HelloShiro {private static final Logger logger =  LoggerFactory.getLogger(HelloShiro.class);public static void main(String[] args) {// 初始化 SecurityManagerFactory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");SecurityManager securityManager = factory.getInstance();SecurityUtils.setSecurityManager(securityManager);// 获取当前用户Subject subject = SecurityUtils.getSubject();// 登录UsernamePasswordToken token = new UsernamePasswordToken("user1", "http://blog.csdn.net/unix21");try {subject.login(token);} catch (AuthenticationException ae) {logger.info("登录失败!");return;}logger.info("登录成功!Hello " + subject.getPrincipal());// 注销subject.logout();}
}

参考:Shiro 那点事儿

跟我学Shiro目录贴

二.源码学习

1.SecurityManager

SecurityManager securityManager = factory.getInstance();

进入public T getInstance()

进入public T createInstance()

public T createInstance() {Ini ini = resolveIni();T instance;if (CollectionUtils.isEmpty(ini)) {log.debug("No populated Ini available.  Creating a default instance.");instance = createDefaultInstance();if (instance == null) {String msg = getClass().getName() + " implementation did not return a default instance in " +"the event of a null/empty Ini configuration.  This is required to support the " +"Factory interface.  Please check your implementation.";throw new IllegalStateException(msg);}} else {log.debug("Creating instance from Ini [" + ini + "]");instance = createInstance(ini);if (instance == null) {String msg = getClass().getName() + " implementation did not return a constructed instance from " +"the createInstance(Ini) method implementation.";throw new IllegalStateException(msg);}}return instance;}

进入protected Ini resolveIni()

protected Ini resolveIni() {Ini ini = getIni();if (CollectionUtils.isEmpty(ini)) {log.debug("Null or empty Ini instance.  Falling back to the default {} file.", DEFAULT_INI_RESOURCE_PATH);ini = loadDefaultClassPathIni();}return ini;}

public Ini getIni()


ini是一个自定义的Class

public class Ini implements Map<String, Ini.Section> {private static transient final Logger log = LoggerFactory.getLogger(Ini.class);public static final String DEFAULT_SECTION_NAME = ""; //empty string means the first unnamed sectionpublic static final String DEFAULT_CHARSET_NAME = "UTF-8";public static final String COMMENT_POUND = "#";public static final String COMMENT_SEMICOLON = ";";public static final String SECTION_PREFIX = "[";public static final String SECTION_SUFFIX = "]";protected static final char ESCAPE_TOKEN = '\\';private final Map<String, Section> sections;/*** Creates a new empty {@code Ini} instance.*/public Ini() {this.sections = new LinkedHashMap<String, Section>();}

跳出protected Ini resolveIni()

回到public T createInstance()

进入protected SecurityManager createInstance(Ini ini)

进入public Section getSection(String sectionName)

进入private static String cleanName(String sectionName)

private static String cleanName(String sectionName) {String name = StringUtils.clean(sectionName);if (name == null) {log.trace("Specified name was null or empty.  Defaulting to the default section (name = \"\")");name = DEFAULT_SECTION_NAME;}return name;}

org.apache.shiro.util的StringUtils

EMPTY_STRING是StringUtils定义的静态常量

public class StringUtils {public static final String EMPTY_STRING = "";public static final char DEFAULT_DELIMITER_CHAR = ',';public static final char DEFAULT_QUOTE_CHAR = '"';

out返回"main"

private static String cleanName(String sectionName)返回"main"

回到public Section getSection(String sectionName)

ini.getSection返回null回到private SecurityManager createSecurityManager(Ini ini)

又到public Section getSection(String sectionName)返回null

public Section getSection(String sectionName) {String name = cleanName(sectionName);return sections.get(name);}

回到private SecurityManager createSecurityManager(Ini ini)

进入createSecurityManager

@SuppressWarnings({"unchecked"})private SecurityManager createSecurityManager(Ini ini, Ini.Section mainSection) {Map<String, ?> defaults = createDefaults(ini, mainSection);Map<String, ?> objects = buildInstances(mainSection, defaults);SecurityManager securityManager = getSecurityManagerBean();boolean autoApplyRealms = isAutoApplyRealms(securityManager);if (autoApplyRealms) {//realms and realm factory might have been created - pull them out first so we can//initialize the securityManager:Collection<Realm> realms = getRealms(objects);//set them on the SecurityManagerif (!CollectionUtils.isEmpty(realms)) {applyRealmsToSecurityManager(realms, securityManager);}}return securityManager;}

进入createDefaults

    protected Map<String, ?> createDefaults(Ini ini, Ini.Section mainSection) {Map<String, Object> defaults = new LinkedHashMap<String, Object>();SecurityManager securityManager = createDefaultInstance();defaults.put(SECURITY_MANAGER_NAME, securityManager);if (shouldImplicitlyCreateRealm(ini)) {Realm realm = createRealm(ini);if (realm != null) {defaults.put(INI_REALM_NAME, realm);}}return defaults;}
protected SecurityManager createDefaultInstance() {return new DefaultSecurityManager();}
public DefaultSecurityManager() {super();this.subjectFactory = new DefaultSubjectFactory();this.subjectDAO = new DefaultSubjectDAO();}
public SessionsSecurityManager() {super();this.sessionManager = new DefaultSessionManager();applyCacheManagerToSessionManager();}
public AuthorizingSecurityManager() {super();this.authorizer = new ModularRealmAuthorizer();}
public AuthenticatingSecurityManager() {super();this.authenticator = new ModularRealmAuthenticator();}
public RealmSecurityManager() {super();}

最终是个空方法

public abstract class CachingSecurityManager implements SecurityManager, Destroyable, CacheManagerAware {private CacheManager cacheManager;public CachingSecurityManager() {}

...之后
回到createDefaults

protected boolean shouldImplicitlyCreateRealm(Ini ini)

protected boolean shouldImplicitlyCreateRealm(Ini ini) {return !CollectionUtils.isEmpty(ini) &&(!CollectionUtils.isEmpty(ini.getSection(IniRealm.ROLES_SECTION_NAME)) ||!CollectionUtils.isEmpty(ini.getSection(IniRealm.USERS_SECTION_NAME)));}

回到createDefaults进入createRealm

IniRealm声明

public class IniRealm extends TextConfigurationRealm {public static final String USERS_SECTION_NAME = "users";public static final String ROLES_SECTION_NAME = "roles";private static transient final Logger log = LoggerFactory.getLogger(IniRealm.class);private String resourcePath;private Ini ini; //reference added in 1.2 for SHIRO-322public IniRealm() {super();}

调用super()的super()

实例化LinkedHashMap和读写锁ReadWriteLock

回到createRealm

回到createDefaults

回到createSecurityManager

进入buildInstances

private Map<String, ?> buildInstances(Ini.Section section, Map<String, ?> defaults) {this.builder = new ReflectionBuilder(defaults);return this.builder.buildObjects(section);}

进入ReflectionBuilder

这行代码很简洁,defaults不为空,所以this.objects指向defaults的引用

this.objects = CollectionUtils.isEmpty(defaults) ? new LinkedHashMap<String, Object>() : defaults;

进入buildObjects 因为kvPairs为null所以直接跳到LifecycleUtils.init(objects.values());

再跳到public static void init(Object o),判断对象不能Initializable

第二次又进入这次对象是可以Initializable

进入

public final void init() {//trigger obtaining the authorization cache if possiblegetAvailableAuthenticationCache();onInit();}

进入getAvailableAuthenticationCache

private Cache<Object, AuthenticationInfo> getAvailableAuthenticationCache() {Cache<Object, AuthenticationInfo> cache = getAuthenticationCache();boolean authcCachingEnabled = isAuthenticationCachingEnabled();if (cache == null && authcCachingEnabled) {cache = getAuthenticationCacheLazy();}return cache;}

返回是null

回到

public final void init() {//trigger obtaining the authorization cache if possiblegetAvailableAuthenticationCache();onInit();}

进入onInit()

@Overrideprotected void onInit() {super.onInit();// This is an in-memory realm only - no need for an additional cache when we're already// as memory-efficient as we can be.Ini ini = getIni();String resourcePath = getResourcePath();if (!CollectionUtils.isEmpty(this.users) || !CollectionUtils.isEmpty(this.roles)) {if (!CollectionUtils.isEmpty(ini)) {log.warn("Users or Roles are already populated.  Configured Ini instance will be ignored.");}if (StringUtils.hasText(resourcePath)) {log.warn("Users or Roles are already populated.  resourcePath '{}' will be ignored.", resourcePath);}log.debug("Instance is already populated with users or roles.  No additional user/role population " +"will be performed.");return;}if (CollectionUtils.isEmpty(ini)) {log.debug("No INI instance configuration present.  Checking resourcePath...");if (StringUtils.hasText(resourcePath)) {log.debug("Resource path {} defined.  Creating INI instance.", resourcePath);ini = Ini.fromResourcePath(resourcePath);if (!CollectionUtils.isEmpty(ini)) {setIni(ini);}}}if (CollectionUtils.isEmpty(ini)) {String msg = "Ini instance and/or resourcePath resulted in null or empty Ini configuration.  Cannot " +"load account data.";throw new IllegalStateException(msg);}processDefinitions(ini);}

super.onInit()也就是protected void onInit()

@Overrideprotected void onInit() {super.onInit();processDefinitions();}

processDefinitions调用processRoleDefinitions(),roleDefinitions为null直接返回到processDefinitions

processUserDefinitions中userDefinitions也是null直接return回processDefinitions了

回到onInit()

返回

返回

回到buildObjects返回objects

回到buildInstances

回到createSecurityManager

private SecurityManager getSecurityManagerBean() {return builder.getBean(SECURITY_MANAGER_NAME, SecurityManager.class);}

进入org.apache.shiro.config的public class ReflectionBuilder

instanceof运算符 只被用于对象引用变量,检查左边的被测试对象 是不是 右边类或接口的 实例化。如果被测对象是null值,则测试结果总是false。 
Class类的isInstance(Object obj)方法,obj是被测试的对象,如果obj是调用这个方法的class或接口 的实例,则返回true。这个方法是instanceof运算符的动态等价。 
Class类的isAssignableFrom(Class cls)方法,如果调用这个方法的class或接口 与 参数cls表示的类或接口相同,或者是参数cls表示的类或接口的父类,则返回true。

instanceof, isinstance,isAssignableFrom的区别

回到createSecurityManager

进入isAutoApplyRealms

realms为null,返回autoApply为true

回到createSecurityManager

进入applyRealmsToSecurityManager

再调用setRealms

回到protected void afterRealmsSet()

回到setRealms

回到

回到

回到

回到

回到

回到

回到最外层调用函数

至此,SecurityManager securityManager = factory.getInstance();才完成。

2.Subject

// 获取当前用户Subject subject = SecurityUtils.getSubject();
public static Subject getSubject() {Subject subject = ThreadContext.getSubject();if (subject == null) {subject = (new Subject.Builder()).buildSubject();ThreadContext.bind(subject);}return subject;}

进入org.apache.shiro.util的public abstract class ThreadContext

getValue

回到public static Subject getSubject()

回到最外层

3.UsernamePasswordToken

UsernamePasswordToken token = new UsernamePasswordToken("user1", "http://blog.csdn.net/unix21");

调用构造函数

private声明

public class UsernamePasswordToken implements HostAuthenticationToken, RememberMeAuthenticationToken {
private String username;
private char[] password;
private boolean rememberMe = false;
private String host;
...

HostAuthenticationToken接口定义

public interface HostAuthenticationToken extends AuthenticationToken {
String getHost();
}public interface AuthenticationToken extends Serializable {
Object getPrincipal();
Object getCredentials();
}

Shiro源码学习之二

Shiro源码学习之一相关推荐

  1. Shiro源码学习之二

    接上一篇 Shiro源码学习之一 3.subject.login 进入login public void login(AuthenticationToken token) throws Authent ...

  2. mutations vuex 调用_Vuex源码学习(六)action和mutation如何被调用的(前置准备篇)...

    前言 Vuex源码系列不知不觉已经到了第六篇.前置的五篇分别如下: 长篇连载:Vuex源码学习(一)功能梳理 长篇连载:Vuex源码学习(二)脉络梳理 作为一个Web前端,你知道Vuex的instal ...

  3. vue实例没有挂载到html上,vue 源码学习 - 实例挂载

    前言 在学习vue源码之前需要先了解源码目录设计(了解各个模块的功能)丶Flow语法. src ├── compiler # 把模板解析成 ast 语法树,ast 语法树优化,代码生成等功能. ├── ...

  4. 2021-03-19Tomcat源码学习--WebAppClassLoader类加载机制

    Tomcat源码学习--WebAppClassLoader类加载机制 在WebappClassLoaderBase中重写了ClassLoader的loadClass方法,在这个实现方法中我们可以一窥t ...

  5. jQuery源码学习之Callbacks

    jQuery源码学习之Callbacks jQuery的ajax.deferred通过回调实现异步,其实现核心是Callbacks. 使用方法 使用首先要先新建一个实例对象.创建时可以传入参数flag ...

  6. JDK源码学习笔记——Integer

    一.类定义 public final class Integer extends Number implements Comparable<Integer> 二.属性 private fi ...

  7. DotText源码学习——ASP.NET的工作机制

    --本文是<项目驱动学习--DotText源码学习>系列的第一篇文章,在这之后会持续发表相关的文章. 概论 在阅读DotText源码之前,让我们首先了解一下ASP.NET的工作机制,可以使 ...

  8. Vuex源码学习(五)加工后的module

    没有看过moduleCollection那可不行!Vuex源码学习(四)module与moduleCollection 感谢提出代码块和截图建议的小伙伴 代码块和截图的区别: 代码块部分希望大家按照我 ...

  9. 我的angularjs源码学习之旅2——依赖注入

    依赖注入起源于实现控制反转的典型框架Spring框架,用来削减计算机程序的耦合问题.简单来说,在定义方法的时候,方法所依赖的对象就被隐性的注入到该方法中,在方法中可以直接使用,而不需要在执行该函数的时 ...

最新文章

  1. 关于数据库备份的问题
  2. 生产环境遇到难题,你是如何解决的?
  3. 通过继承来实现注解方式的属性注入
  4. python3.6,--登录知乎
  5. 【PL/SQL】处理数据
  6. C++中数字与字符串之间的转换
  7. linux /etc/security/limits.conf的相关说明
  8. poj 1226 Substrings kmp 好题,我调试了一晚上啊!!汗
  9. 网络黑客节庆狂欢 趋势科技见招拆招
  10. html 图片分散,纯js和CSS3分散式宝丽来图片画廊
  11. Mac系统最强虚拟机(支持Big Sur)
  12. 删除oracle安装目录,Oracle 卸载
  13. Solidworks 2015 安装教程
  14. 看完此篇文章可以快速熟悉Spring事务
  15. 三点运算符(...)的使用
  16. c++字符串转换为数字(stoi, stol, stoul, stoull, stof, stod, stold)
  17. 海思Hi3516EV200开发第一天
  18. 手机闪存速度排行_手机很卡可能是只是因为闪存颗粒太差 EMMC UFS大对比
  19. 几种编程语言类型的区分
  20. VIVADO时序约束之Input Delay(set_input_delay)

热门文章

  1. 【lidar】3D目标检测PointPillars:论文解读、代码解读、部署实现(1)
  2. 深度学习 -- TensorFlow(9)循环神经网络RNN
  3. python opencv单通道转多通道_13、OpenCV绘图和文本显示
  4. 开源点云实时压缩方案测试
  5. Blender与UE5完美结合全流程创作游戏资产视频教程
  6. 《Bigtable:a distributed storage system for struct data》笔记
  7. 排序算法7---快速排序算法
  8. Ubuntu 16.04安装QQ(不一定成功)
  9. Python函数中的参数(一)
  10. Cron表达式的详细用法