感谢作者:本文来源 http://www.iocoder.cn/Shiro/xiaoqiyiye/intro/
- SecurityManager :安全管理,Shiro最核心的组件,Shiro通过SecurityMananger 来管理内部组件的实例,初始化实例。并通过他来提供安全管理的各种服务。
- Authenticator:认证器,认证AuthenticationToken是否有效
- Authorizer:授权器,处理角色和权限。
- subject:当前操纵主体,表示当前操作的用户
- SubjectContext:Subject 上下文数据对象
- AuthenticationToken:认证token信息,(用户名和密码)
- ThreadContext:线程上线问对象,负责绑定对象当前线程
在学习和使用Shiro过程中,我们知道SecurityManager接口时Shireo中最合性的接口,我们就沿着这个接口进行分析下面的代码是SecurityManager接口的定义:
public interface SecurityManager extends Authenticator, Authorizer, SessionManager { //认证器 //授权器 /** * 登录 */ Subject login(Subject subject, AuthenticationToken authenticationToken) throws AuthenticationException; /** * 登出 */ //操作主题当前用户 void logout(Subject subject); /** * 创建Subject */ Subject createSubject(SubjectContext context); }
在SecurityManager 中有三个方法,一个是登陆,等处,创建Object 。通常我们是这么使用的,
- 首先创建Subject对象,
- 然后通过调用login方法传入认证信息token对登陆进行认证。
Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123"); subject.login(token);
SecurityUtils 分析
在Shiro中提供了一个方便使用的工具类SecurityUtils,SecurityUtils核心功能是获取SecurityManager ,以及获取subject
1. 获取SecurityManager
private static 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); } return securityManager; }
2. 获取Subject
public static Subject getSubject() { Subject subject = ThreadContext.getSubject(); if (subject == null) { subject = (new Subject.Builder()).buildSubject(); ThreadContext.bind(subject); } return subject; }
在上边的额代码中重要的是通过Subject.builder 类提供buildSuject()来创建的,在创建Suject的同事还创建了SubjectContext。也就是说,Subject和SubjectContext是一对,下面的代码时Subject.Builder类构造器
public Builder(SecurityManager securityManager) { if (securityManager == null) { throw new NullPointerException("SecurityManager method argument cannot be null."); } this.securityManager = securityManager; // 创建了SubjectContext实例对象 this.subjectContext = newSubjectContextInstance(); if (this.subjectContext == null) { throw new IllegalStateException("Subject instance returned from 'newSubjectContextInstance' " + "cannot be null."); } this.subjectContext.setSecurityManager(securityManager); }
而buildSubject()实际上就是调用SecurityManager接口中的CreateSubject(subjectContext subjectContext)方法
public Subject buildSubject() { return this.securityManager.createSubject(this.subjectContext); }