一.最基本的使用
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.youkuaiyun.com/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.youkuaiyun.com/unix21");
try {
subject.login(token);
} catch (AuthenticationException ae) {
logger.info("登录失败!");
return;
}
logger.info("登录成功!Hello " + subject.getPrincipal());
// 注销
subject.logout();
}
}
参考: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 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>();
}
跳出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 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() {
}
...之后
回到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-322
public 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 possible
getAvailableAuthenticationCache();
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 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了
回到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.youkuaiyun.com/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();
}