[置顶] 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


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) {
        // 初始化 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源码学习之一_第1张图片


参考:Shiro 那点事儿

跟我学Shiro目录贴


二.源码学习

1.SecurityManager

SecurityManager securityManager = factory.getInstance();


进入public T getInstance()

[置顶] Shiro源码学习之一_第2张图片

进入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()

[置顶] Shiro源码学习之一_第3张图片
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()

[置顶] Shiro源码学习之一_第4张图片


进入protected SecurityManager createInstance(Ini ini)

[置顶] Shiro源码学习之一_第5张图片


进入public Section getSection(String sectionName)

[置顶] Shiro源码学习之一_第6张图片


进入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

[置顶] Shiro源码学习之一_第7张图片


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"

[置顶] Shiro源码学习之一_第8张图片


回到public Section getSection(String sectionName)

[置顶] Shiro源码学习之一_第9张图片


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

[置顶] Shiro源码学习之一_第10张图片

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

[置顶] Shiro源码学习之一_第11张图片


回到createDefaults


回到createSecurityManager

[置顶] Shiro源码学习之一_第12张图片


进入buildInstances

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

进入ReflectionBuilder

[置顶] Shiro源码学习之一_第13张图片


[置顶] Shiro源码学习之一_第14张图片

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

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



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

[置顶] Shiro源码学习之一_第15张图片


[置顶] Shiro源码学习之一_第16张图片

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



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

[置顶] Shiro源码学习之一_第17张图片

进入

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();
    }


进入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();
    }


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


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

[置顶] Shiro源码学习之一_第18张图片


回到onInit()

返回

[置顶] Shiro源码学习之一_第19张图片

返回



回到buildObjects返回objects

[置顶] Shiro源码学习之一_第20张图片


回到buildInstances



回到createSecurityManager


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


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

[置顶] Shiro源码学习之一_第21张图片

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

[置顶] Shiro源码学习之一_第22张图片


进入applyRealmsToSecurityManager


再调用setRealms

[置顶] Shiro源码学习之一_第23张图片


回到protected void afterRealmsSet()



回到setRealms


回到


回到

[置顶] Shiro源码学习之一_第24张图片

回到

[置顶] Shiro源码学习之一_第25张图片

回到

[置顶] Shiro源码学习之一_第26张图片

回到


回到

[置顶] Shiro源码学习之一_第27张图片


回到最外层调用函数

[置顶] Shiro源码学习之一_第28张图片

至此,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

[置顶] Shiro源码学习之一_第29张图片

回到public static Subject getSubject()

[置顶] Shiro源码学习之一_第30张图片


回到最外层



3.UsernamePasswordToken

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


[置顶] Shiro源码学习之一_第31张图片

[置顶] Shiro源码学习之一_第32张图片


调用构造函数

[置顶] Shiro源码学习之一_第33张图片


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源码学习之一_第34张图片

Shiro源码学习之二

你可能感兴趣的:([置顶] Shiro源码学习之一)