Shiro登录校验流程实现与分析

什么是Shiro

Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。

三个核心组件

Subject, SecurityManager 和 Realms.
①Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。但考虑到大多数目的和用途,你可以把它认为是Shiro的“用户”概念。Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
②SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
③Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。

登录认证过程简述

①调用subject.login方法进行登录,其会自动委托给securityManager,login方法进行登录;
②securityManager通过 Authenticator(认证器)进行认证
③Authenticator的实现ModularRealmAuthenticaton调用realm从ini配置文件取用户真实的账号和密码,这里使用的是IniRealm ( shiro自带,相当于数据源) ;

④IniRealm先根据token中的账号去ini中找该账号,如果找不到则给ModularRealmAuthenticator返回null ,如果找到则匹配密码,匹配密码成功则认证通过。
image.png
具体实现
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.1.3</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core -->
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-core</artifactId>
      <version>1.4.0</version>
    </dependency>
image.png
package com.swl;

import org.apache.shiro.SecurityUtils;
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.junit.Test;

/**
 * <Description>ShiroTest<br>
 *
 * @author DaShi<br>
 * @CreateDate 2019-02-15 09:43 <br>
 */
public class ShiroTest {
    @Test
    public void loginTest() throws Exception{
        //创建IniSecurityManager工程对象:加载配置文件
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        //通过工厂对象创建SecurityManager对象
        SecurityManager securityManager = factory.getInstance();
        // 将SecurityManager绑定到当前运行环境中,让系统随时可以访问SecurityManager对象
        SecurityUtils.setSecurityManager(securityManager);

        //创建登录主体 注意:此时主体没有经过验证,仅仅是个空的对象
        Subject subject = SecurityUtils.getSubject();
        //绑定主体登陆的身份、凭证 即账号密码
        UsernamePasswordToken token = new UsernamePasswordToken("zhangsan","666");
        //主体登陆
        try{
            subject.login(token);
        }catch (Exception e){
            //抛错误
        }
        //登陆判断
        System.out.println("登录结果" + subject.isAuthenticated() );
        //登出判断
        subject.logout();
        System.out.println("登出结果" + subject.isAuthenticated());
    }
}

结果:


image.png
源码分析

①我们在登录操作时打好断点,debug运行
image.png

②我们进入到subject主体的实现类中,注意标记部分,subject将登录操作委托给了securitymanager,参数除了页面传入的token以外还有subject主体
image.png
③进入到securitymanager实现类中,开始执行认证方法
image.png

④点进去看一下,我们发现securitymanager将认证任务委托给了认证器,由认证器执行认证方法
image.png

⑤我们进入到认证方法中
image.png
⑥继续执行doAuthenticate,我们发现这里面有个realm,他是啥呢?
image.png
我们看到realms这个集合里面其实就是我们之前加载的realms.ini中的内容
image.png
⑦因为我们只有一个realm,所以进入了true条件中,这时我们刚才标记出的AuthenticationInfo出现了,看看他是啥
image.png
点进去看看
image.png

看不懂,继续进去看看,我们看到他先把我们的token包装成了 UsernamePasswordToken的形式 然后执行了getuser()参数是我们页面传进来的token的name
image.png
⑧我们看一下里面是什么,是通过页面传入的那个用户名,去我们刚才realm里面的user列表去查找有没有这个用户 如果找到了,将realm中该用户信息返回上一层
image.png

⑨这时我们可以看到account中包含了张三的信息
image.png
⑩接下来我们继续返回上一层,因为我们已经在realm中找到了页面输入的token的用户名,下一步进行密码验证
image.png
密码验证就很简单了,重点就是这个判断
image.png
其实就是把我们刚才取得的那个realm中的张三的密码和我们页面传入的密码比较
image.png

好了整个过程大概就是这个样子啦!!!
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容