shiro的源码分析(一)

(一)//1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
Factory factory =  new IniSecurityManagerFactory("classpath:shiro.ini")
2.factory类的类结构为:
 

(3)abstractFactory类主要设置是否单例

(4)iniFactorySupport是支持ini设置创建的对象

(5)iniSecuritymanagerFactory是ini方式创建securityManager的实现类

(二)//2、得到SecurityManager实例 并绑定给SecurityUtils
org.apache.shiro.mgt.SecurityManagersecurityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
(1)通过创建的Ini对象创建Securitymanager对象
1  IniSecurityManagerFactory类:
2      creatSecuritymanager(ini){
3      SecurityManager securityManager = createSecurityManager(ini);
4      return securityManager;
5  }

 

(2)通过创建的Ini对象创建Securitymanager对象
 1 private SecurityManager createSecurityManager(Ini ini) {
 2 //null
 3 Ini.Section mainSection = ini.getSection(MAIN_SECTION_NAME);
 4 if (CollectionUtils.isEmpty(mainSection)) {
 5 
 6 //try the default: null
 7 mainSection = ini.getSection(Ini.DEFAULT_SECTION_NAME);
 8 }
 9  return createSecurityManager(ini, mainSection);
10  }

 (3)通过ini对象和主模块mainSession创建Securitymanager

 1 private SecurityManager createSecurityManager(Ini ini, Ini.Section mainSection) {
 2 //{securityManager=DefaultSecurityManager,iniRealm=IniRealm}  
 3 Map defaults = createDefaults(ini, mainSection);
 4 Map objects = buildInstances(mainSection, defaults);
 5 
 6 SecurityManager securityManager = getSecurityManagerBean();
 7 boolean autoApplyRealms = isAutoApplyRealms(securityManager);
 8 if (autoApplyRealms) {
 9 //realms and realm factory might have been created - pull them out first  so we can initialize the securityManager:
10  Collection realms = getRealms(objects);
11  //set them on the SecurityManager
12  if (!CollectionUtils.isEmpty(realms)) {
13          applyRealmsToSecurityManager(realms, securityManager);
14            }
15         }
16        return securityManager;
17     }
(4)通过mainSession和默认object对象设置对象之间的关联
 1 private Map buildInstances(Ini.Section section, Map defaults) {
 2      this.builder = new ReflectionBuilder(defaults);
 3      return this.builder.buildObjects(section);
 4  5 //类ReflectionBuilder
 6 //通过mainSection创建对象并关联
 7  public Map buildObjects(Map kvPairs) {
 8   .....
 9  LifecycleUtils.init(objects.values());
10
 (5)因为IniRealm实现了Initializable,则初始化IniRealm对象
 1 //类IniRealm
 2 private void processDefinitions(Ini ini) {
 3  Ini.Section usersSection = ini.getSection(USERS_SECTION_NAME);
 4  processUserDefinitions(usersSection);
 5 }
 6 //通过userSection解析user模块
 7  protected void processUserDefinitions(Map userDefs) {
 8       for (String username : userDefs.keySet()) {
 9          ........
10       account = new SimpleAccount(username, password, getName());
11       add(account);
12         ........
13        }
14 15 protected void add(SimpleAccount account) {
16    String username = getUsername(account);
17    USERS_LOCK.writeLock().lock();
18    try {
19     this.users.put(username, account);
20    }finally {
21     USERS_LOCK.writeLock().unlock();
22 }
IniRealm的类结构为:

simpleAccount的结构为:
至此,创建对象关联,IniRealm的初始化完成!接下来看DefaultSecurityManager的结构图:

(7)设置DefaultSecurityManager的realm属性:
1  applyRealmsToSecurityManager(realms, securityManager){
2     ((RealmSecurityManager) securityManager).setRealms(realms);
3 4 //在类RealmSecurityManager中
5 public void setRealms(Collection realms) {
6    this.realms = realms;
7    afterRealmsSet();
8

 注意:afterRealmsSet();主要用来设置authenticator、authorizer的realm属性:

           至此DefaultSecurityManager的属性设置完成、并返回DefaultSecurityManager对象
//3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
Subject subject = SecurityUtils.getSubject();
 
1 //获取主题对象 
2 public static Subject getSubject() {
3     Subject subject = ThreadContext.getSubject();//第一次null
4     if (subject == null) {
5        subject = (new Subject.Builder()).buildSubject();
6        ThreadContext.bind(subject);
7         }
8       return subject;
9 }

 

(1)代码分析:使用建造者模式创建对象:

 1 public static class Builder{
 2        SubjectContext subjectContext;
 3        SecurityManager securityManager;
 4         public Builder(SecurityManager securityManager) {
 5             if (securityManager == null) {
 6                 throw new NullPointerException("SecurityManager method argument cannot be null.");
 7             }
 8             this.securityManager = securityManager;
 9             this.subjectContext = newSubjectContextInstance();//DefaultSubjectContext(初始化一个backMap集合)
10             if (this.subjectContext == null) {
11                 throw new IllegalStateException("Subject instance returned from 'newSubjectContextInstance' " +
12                         "cannot be null.");
13             }
14             this.subjectContext.setSecurityManager(securityManager);
15         }
16        public Subject buildSubject() {
17             return this.securityManager.createSubject(this.subjectContext);
18         }
19

 (2)使用主题上下文创建主题

 1   public Subject createSubject(SubjectContext subjectContext) {
 2         //create a copy so we don't modify the argument's backing map:
 3         SubjectContext context = copy(subjectContext);
 4 
 5         //ensure that the context has a SecurityManager instance, and if not, add one:
 6         context = ensureSecurityManager(context);//DefaultSubjectContext.backMap.put(SecurityManage)
 7 
 8         //Resolve an associated Session (usually based on a referenced session ID), and place it in the context before
 9         //sending to the SubjectFactory.  The SubjectFactory should not need to know how to acquire sessions as the
10         //process is often environment specific - better to shield the SF from these details:
11         context = resolveSession(context);
12 
13         //Similarly, the SubjectFactory should not require any concept of RememberMe - translate that here first
14         //if possible before handing off to the SubjectFactory:
15         context = resolvePrincipals(context);
16 
17         Subject subject = doCreateSubject(context);
18 
19         //save this subject for future reference if necessary:
20         //(this is needed here in case rememberMe principals were resolved and they need to be stored in the
21         //session, so we don't constantly rehydrate the rememberMe PrincipalCollection on every operation).
22         //Added in 1.2:
23         save(subject);
24 
25         return subject;
26     }

 (3)通过主题创建subject对象

 protected Subject doCreateSubject(SubjectContext context) {
        return getSubjectFactory().createSubject(context);
    }

 

(4)DefaultSubjectFactory创建主题对象:
 1    public Subject createSubject(SubjectContext context) {
 2         SecurityManager securityManager = context.resolveSecurityManager();
 3         Session session = context.resolveSession();
 4         boolean sessionCreationEnabled = context.isSessionCreationEnabled();
 5         PrincipalCollection principals = context.resolvePrincipals();
 6         boolean authenticated = context.resolveAuthenticated();
 7         String host = context.resolveHost();
 8
 9         return new DelegatingSubject(principals, authenticated, host, session, sessionCreationEnabled, securityManager);
10     }

 到些sujbect对象创建完成,并把sujbect绑定到保存到本地变量和线程

 UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");

//4、登录,即身份验证
subject.login(token);

(1)通过token登录.token失败,则抛出异常

 public void login(AuthenticationToken token) throws AuthenticationException {
......
 Subject subject = securityManager.login(this, token);
......
}
//在DefaultSecurityManager中
  public Subject login(Subject subject, AuthenticationToken token) 
  throws AuthenticationException {
  try{AuthenticationInfo info = authenticate(token);}catch{...}
  Subject loggedIn = createSubject(token, info, subject);
  onSuccessfulLogin(token, info, loggedIn);
  return loggedIn;
}

(2)多模块身份验证器类验证token(之前realm被设置于ModularRealmAuthenticator,只有一个iniRealm,故执行doSingleRealmAuthentication)

protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, AuthenticationToken token) {
        if (!realm.supports(token)) {
            String msg = "Realm [" + realm + "] does not support authentication token [" +
                    token + "].  Please ensure that the appropriate Realm implementation is " +
                    "configured correctly or that the realm accepts AuthenticationTokens of this type.";
            throw new UnsupportedTokenException(msg);
        }
        AuthenticationInfo info = realm.getAuthenticationInfo(token);
        if (info == null) {
            String msg = "Realm [" + realm + "] was unable to find account data for the " +
                    "submitted AuthenticationToken [" + token + "].";
            throw new UnknownAccountException(msg);
        }
        return info;
    }

 (3)通过realm身份验证:首先是 SimpleAccountRealm进行用户名判断:

  
public class SimpleAccountRealm extends AuthorizingRealm {
.......
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken upToken = (UsernamePasswordToken) token; SimpleAccount account = getUser(upToken.getUsername()); if (account != null) { if (account.isLocked()) { throw new LockedAccountException("Account [" + account + "] is locked."); } if (account.isCredentialsExpired()) { String msg = "The credentials for account [" + account + "] are expired"; throw new ExpiredCredentialsException(msg); } } return account; }}

 (4)info存在,则密码验证:

public class SimpleCredentialsMatcher extends CodecSupport implements CredentialsMatcher {
     public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        Object tokenCredentials = getCredentials(token);
        Object accountCredentials = getCredentials(info);
       return equals(tokenCredentials, accountCredentials);
     }

 

 

 

 

 

转载于:https://www.cnblogs.com/pingqlin341/p/7168863.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值