Shiro源码学习之一
一.最基本的使用
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
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 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() {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;}
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;
再跳到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();}
@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();}
processUserDefinitions中userDefinitions也是null直接return回processDefinitions了
回到onInit()
返回
返回
回到buildObjects返回objects
回到buildInstances
回到createSecurityManager
private SecurityManager getSecurityManagerBean() {return builder.getBean(SECURITY_MANAGER_NAME, SecurityManager.class);}
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");
調用構造函數
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源码学习之一的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 常用Maven收集以及Maven技巧
- 下一篇: Shiro源码学习之二