zoukankan      html  css  js  c++  java
  • 深入浅出Shiro系列

    写在前面:

    小伙伴儿们,大家好!这次让我们一起来学习Shiro权限框架吧!

    思维导图:

    1,初识Shiro

    1.1,简介;

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

    1.2,入门配置;

    创建Maven工程命名为Shiro,结构图如下;

    直接引入依赖:

    <dependencies>
    
        <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core -->
        <dependency>
          <groupId>org.apache.shiro</groupId>
          <artifactId>shiro-core</artifactId>
          <version>1.5.3</version>
        </dependency>
    
        <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
        <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-log4j12</artifactId>
          <version>2.0.0-alpha1</version>
        </dependency>
    
        <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
        <dependency>
          <groupId>commons-logging</groupId>
          <artifactId>commons-logging</artifactId>
          <version>1.2</version>
        </dependency>
        
      </dependencies>
     

    log4j.properties配置文件:

    log4j.rootLogger=INFO, stdout

    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%d %[%c] - %m %n

    General Apache libraries
    log4j.logger.org.apache=WARN

    Spring
    log4j.logger.org.springframework=WARN

    Default Shiro logging
    log4j.logger.org.apache.shiro=TRACE

    Disable verbose logging
    log4j.logger.org.apache.shiro.util.ThreadContext=WARN
    log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN

    shiro.ini文件(放在resources目录下),以键值对地形式存放:

    [users]
    java=123456
    jack=123

    1.3,程序文件;

    我们新建一个HelloWorld类:

    package com.java;
    
    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;
    
    public class HelloWorld {
    
        public static void main(String[] args) {
            // 读取配置文件,初始化SecurityManager工厂
            Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:shiro.ini");
            // 获取securityManager实例
            SecurityManager securityManager=factory.getInstance();
            // 把securityManager实例绑定到SecurityUtils
            SecurityUtils.setSecurityManager(securityManager);
            // 得到当前执行的用户
            Subject currentUser=SecurityUtils.getSubject();
            // 创建token令牌,用户名/密码
            UsernamePasswordToken token=new UsernamePasswordToken("java", "123456");
            try{
                // 身份认证
                currentUser.login(token);
                System.out.println("身份认证成功!");
            }catch(AuthenticationException e){
                e.printStackTrace();
                System.out.println("身份认证失败!");
            }
            // 退出
            currentUser.logout();
        }
    }
     
    • 首先通过 new IniSecurityManagerFa ctory 并指定一个 ini 配置文件来创建一个 SecurityManager 工厂;
    • 接着获取 SecurityManager 并绑定到 SecurityUtils,这是一个全局设置,设置一次即可;
    • 通过 SecurityUtils 得到 Subject,其会自动绑定到当前线程;如果在 web 环境在请求结束时需要解除绑定;然后获取身份验证的 Token,如用户名 / 密码;
    • 调用 subject.login 方法进行登录,其会自动委托给 SecurityManager.login 方法进行登录;
    • 如果身份验证失败请捕获 Authenticat ionException 或其子类,常见的如: DisabledAccountException(禁用的帐号)、LockedAccountException(锁定的帐号)、UnknownAccountExceptio n(错误的帐号)、ExcessiveAttempts Exception(登录失败次数过多)、In correctCredentialsException (错误的凭证)、ExpiredCredentialsException (过期的凭证)等,具体请查看其继承关系;对于页面的错误消息展示,最好使用如 “用户名 / 密码错误” 而不是 “用户名错误”/“密码错误”,防止一些恶意用户非法扫描帐号库;
    • 最后可以调用 subject.logout 退出,其会自动委托给 SecurityManager.logout 方法退出。

    运行:

    从如上代码可总结出身份验证的步骤

    1. 收集用户身份 / 凭证,即如用户名 / 密码;
    2. 调用 Subject.login 进行登录,如果失败将得到相应的 AuthenticationException 异常,根据异常提示用户错误信息;否则登录成功;
    3. 最后调用 Subject.logout 进行退出操作。

    2,Shiro身份认证;

    2.1,Subject认证主体;

    在 shiro 中,用户需要提供 principals (身份)和 credentials(证明)给 shiro,从而应用能验证用户身份:

    principals:身份,即主体的标识属性,可以是任何东西,如用户名、邮箱等,唯一即可。一个主体可以有多个 principals ,但只有一个 Primary principals,一般是用户名 / 密码 / 手机号。

    credentials:证明 / 凭证,即只有主体知道的安全值,如密码 / 数字证书等。 最常见的 principals 和 credentials 组合就是用户名 / 密码了。接下来先进行一个基本的身份认证。 另外两个相关的概念是之前提到的 SubjectRealm,分别是主体及验证主体的数据源。

    2.2,身份认证流程;

    流程如下:

    1. 首先调用 Subject.login(token) 进行登录,其会自动委托给 Security Manager ,调用之前必须通过 SecurityUtils.set SecurityManager() 设置;
    2. SecurityManager 负责真正的身份验证逻辑;它会委托给 Authenticator 进行身份验证;
    3. Authenticator 才是真正的身份验证者,Shiro API 中核心的身份认证入口点,此处可以自定义插入自己的实现;
    4. Authenticator 可能会委托给相应的 AuthenticationStrategy 进行多 Realm 身份验证,默认 ModularRealmAuthen ticator 会调用 AuthenticationStrategy 进行多 Realm 身份验证;
    5. Authenticator 会把相应的 token 传入 Realm,从 Realm 获取身份验证信息,如果没有返回 / 抛出异常表示身份验证失败了。此处可以配置多个 Realm,将按照相应的顺序及策略进行访问。

    2.3,Realm;

    Realm:域,Shiro 从从 Realm 获取安全数据(如用户、角色、权限),就是说 SecurityManager 要验证用户身份,那么它需要从 Realm 获取相应的用户进行比较以确定用户身份是否合法;也需要从 Realm 得到用户相应的角色 / 权限进行验证用户是否能进行操作;可以把 Realm 看成 DataSource,即安全数据源。如我们之前的 ini 配置方式将使用 org.apache.shiro .realm.text.IniRealm。

    realm种类很多,例如常见的 jdbc realm,jndi realm,text realm,我们这里就了解一下jdbc realm,其他的不做叙述;

    • 首先先建立数据库db_shiro,然后添加表users(表名称不可改),添加一条数据;

    • 配置文件jdbc_realm.ini,这与上文的shiro.ini是一样的;

      [main]
      jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
      dataSource=com.alibaba.druid.pool.DruidDataSource
      dataSource.driverClassName=com.mysql.jdbc.Driver
      dataSource.url=jdbc:mysql://localhost:3306/db_shiro
      dataSource.username=root
      dataSource.password=123456
      jdbcRealm.dataSource=$dataSource
      securityManager.realms=$jdbcRealm
    • 导入依赖

      <!-- mysql 数据库及 druid 连接池-->
          <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.25</version>
          </dependency>
          <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>0.2.23</version>
          </dependency>
    • 测试程序(把路径更改一下即可)

      package com.java;
      
      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;
      
      public class JdbcRealmTest {
      
          public static void main(String[] args) {
              // 读取配置文件,初始化SecurityManager工厂
              Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:jdbc_realm.ini");
              // 获取securityManager实例
              SecurityManager securityManager=factory.getInstance();
              // 把securityManager实例绑定到SecurityUtils
              SecurityUtils.setSecurityManager(securityManager);
              // 得到当前执行的用户
              Subject currentUser=SecurityUtils.getSubject();
              // 创建token令牌,用户名/密码
              UsernamePasswordToken token=new UsernamePasswordToken("java", "123");
              try{
                  // 身份认证
                  currentUser.login(token);
                  System.out.println("身份认证成功!");
              }catch(AuthenticationException e){
                  e.printStackTrace();
                  System.out.println("身份认证失败!");
              }
              // 退出
              currentUser.logout();
          }
      }
       
    • 运行结果


    好了,今天就先分享到这里了,下期继续给大家带来Shiro相关方面的学习! 更多干货、优质文章,欢迎关注我的原创技术公众号~

  • 相关阅读:
    莫比乌斯反演学习笔记
    NOIp 2020 游记
    题解【LOJ3087】「GXOI / GZOI2019」旅行者
    题解【CF999E】Reachability from the Capital
    题解【LOJ2007】「SCOI2015」国旗计划
    题解【LOJ3145】「APIO2019」桥梁
    题解【LOJ2114】「HNOI2015」菜肴制作
    CSP-J/S 2020 爆炸记
    题解【洛谷P2569】[SCOI2010]股票交易
    补题目录
  • 原文地址:https://www.cnblogs.com/huke123/p/13207530.html
Copyright © 2011-2022 走看看