Shiro学习(一)-Shiro入门开发及源码分析

shiro总结

shiro中常用对象和概念

  • 三大常用对象
  1. Subject 主体
  2. principal:身份信息(用户名/账号)
  3. credential:凭证信息(用户密码)
  • 五个主要概念
  1. Subject主体对象
    subject是访问系统的用户,其中用户,程序都可称为主体,凡事要认证的对象都称为主体
  2. SecurityManager安全管理器
    shiro的核心,负责对以下组件的调用和交互,用来完成subject委托的各种功能,比如认证和授权,地位相当于SpringMVC的前端控制器
  3. Realm连接器/安全数据源
    是shiro与安全数据间的桥梁或者连接器,可以看作是DataSource(安全数据源)
  4. Authenticato认证器
    负责主体认证的
  5. Authorizer授权器或者访问控制器
    用来决定主体是否有权限进行相应的操作;即控制着用户能访问应用中的哪些功能

HelloWorld程序源码分析

  • HelloWorld实现
    先引入shiro相关依赖
 <properties>
        <shiro.version>1.3.2shiro.version>
 properties>

	<dependencies>
        <dependency>
            <groupId>org.apache.shirogroupId>
            <artifactId>shiro-coreartifactId>
            <version>${shiro.version}version>
        dependency>
        
        <dependency>
            <groupId>org.apache.shirogroupId>
            <artifactId>shiro-webartifactId>
            <version>${shiro.version}version>
        dependency>
        
        <dependency>
            <groupId>org.apache.shirogroupId>
            <artifactId>shiro-springartifactId>
            <version>${shiro.version}version>
        dependency>
        
        <dependency>
            <groupId>org.apache.shirogroupId>
            <artifactId>shiro-ehcacheartifactId>
            <version>${shiro.version}version>
        dependency>
        <dependency>
            <groupId>commons-logginggroupId>
            <artifactId>commons-loggingartifactId>
            <version>1.2version>
        dependency>
        <dependency>
            <groupId>commons-collectionsgroupId>
            <artifactId>commons-collectionsartifactId>
            <version>3.2.1version>
        dependency>
        
        <dependency>
            <groupId>net.mingsoftgroupId>
            <artifactId>shiro-freemarker-tagsartifactId>
            <version>1.0.0version>
        dependency>
    dependencies>
  1. 项目根路径加上shiro.ini添加
    #配置自定义的Realm,注意需要我们自定义的realm的权限定名
    myRealm=cn.wolfcode.crm.shiro.realm.MyRealm
    #指定安全管理器的realms实现
    securityManager.realms=$myRealm
  1. 自定义我们的realm,注意权限定名是cn.wolfcode.crm.shiro.realm.MyRealm
    public class MyRealm extends AuthorizingRealm {
        //权限认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            //模拟数据库数据
            String username = "chenjin";
            String password = "123";

            //获取token中的身份
            String principal = (String) token.getPrincipal();
            //比对数据库信息与传来的token
            if(username.equals(principal)){
                return new SimpleAuthenticationInfo(username,password,getName());
            }
            return null;
        }
    }
  1. 编写测试类进行权限认证
    //安全管理器工厂
    IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
    //获取安全管理器,SecurityManager是实现shiro功能(登录,认证,授权)的核心
    SecurityManager manager = factory.getInstance();
    //设置安全管理器运行环境
    SecurityUtils.setSecurityManager(manager);
    //从当前运行环境中取出一个主体对象,subject是访问系统的用户,会调用安全管理器去执行
    Subject subject = SecurityUtils.getSubject();
    //创建token,包含用户名和密码
    UsernamePasswordToken token = new UsernamePasswordToken("chenjin", "123");
    System.out.println("当前认证状态:"+subject.isAuthenticated());
    try {
        subject.login(token);
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println("当前认证状态:"+subject.isAuthenticated());
    subject.logout();
    System.out.println("当前认证状态:"+subject.isAuthenticated());
  • 源码分析
    上述核心代码为subject.login(token);debug进入后观察发现如下
  1. DelegatingSubject中存有securityManager,因此他会调用securityManager进行权限认证
    this.securityManager.login(this, token);
   public void login(AuthenticationToken token) throws AuthenticationException {
       Subject subject = this.securityManager.login(this, token);
   }
  1. 安全管理器(SecurityManager)调用权限认证器(Authenticator),执行认证
    this.authenticator.authenticate(token) :其中this就是AuthenticatingSecurityManager对象
  public AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {
       return this.authenticator.authenticate(token);
   }
  1. ModularRealmAuthenticator(权限认证器)中有Realm对象,Realm是安全数据源
    自认证器中会执行this.doSingleRealmAuthentication(realms, authenticationToken)进行认证
   protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, AuthenticationToken token) {
       //realm是AuthenticatingRealm对象
       AuthenticationInfo info = realm.getAuthenticationInfo(token);  
       //info不存在,抛出未知账户异常UnknownAccountException
       if (info == null) {
               String msg = "Realm [" + realm + "] was unable to find account data for the submitted AuthenticationToken [" + token + "].";
               throw new UnknownAccountException(msg);
       }
   }
  1. 在AuthenticatingRealm中的方法
    public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        AuthenticationInfo info = this.getCachedAuthenticationInfo(token);
        if (info == null) {
            //如果我们定义了自己的realm下边的this就是我们自定义的;否则进入SimpleAccountRealm
            //执行我们自定义realm中的方法返回权限认证信息,如果info不为空说明身份正确,返回的info中包含安全数据源的身份和凭证,便于下边进行凭证进行匹配
            info = this.doGetAuthenticationInfo(token);

            log.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info);
            if (token != null && info != null) {
                this.cacheAuthenticationInfoIfPossible(token, info);
            }
        } else {
            log.debug("Using cached authentication info [{}] to perform credentials matching.", info);
        }

        if (info != null) {

            //token中的凭证和我们获得的安全凭证进行匹配,不匹配抛出不正确的凭证异常IncorrectCredentialsException
            this.assertCredentialsMatch(token, info); 
        } else {
            log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}].  Returning null.", token);
        }

        return info;
    }
  • 总结如下:调用关系如下所示
    subject->securityManager->Authenticator->AuthenticatingRealm会调用我们自定义ream返回AuthenticationInfo,如果不为空,将继续判断安全凭证与token中的是否匹配。

在下一篇文章中,我们将进一步阐述如何在web环境下集成Shiro

你可能感兴趣的:(Shiro学习(一)-Shiro入门开发及源码分析)