一.最基本的使用
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>
[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) { // 初始化 SecurityManager Factory<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()
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 section public 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>(); }
回到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); }
进入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 SecurityManager if (!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() { }
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))); }
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-322 public IniRealm() { 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); }
这行代码很简洁,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 possible getAvailableAuthenticationCache(); onInit(); }
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 possible getAvailableAuthenticationCache(); onInit(); }
@Override protected 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()
@Override protected void onInit() { super.onInit(); processDefinitions(); }
processUserDefinitions中userDefinitions也是null直接return回processDefinitions了
返回
返回
回到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源码学习之二