shiro-第一篇-基本介绍及使用

shiro

概述

shior的话,在第一次听说的时候单纯的任务它就是一个安全框架,可以对访问接口的用户进行验证等工作,类似拦截器或过滤器的东西,但是在学习后,发现远远不止这些,它的灵活性和易用性让我震惊,这么好的东西早就应该发现的呀!!!

特性

​ 既然说了它这么好,让我们来看看它到底好在哪里:

易于使用:使用 Shiro 构建系统安全框架非常简单。就算第一次接触也可以快速掌握。

全面:Shiro 包含系统安全框架需要的功能,满足安全需求的“一站式服务”。

灵活:Shiro 可以在任何应用程序环境中工作。虽然它可以在 Web、EJB 和 IoC 环境 中工作,但不需要依赖它们。Shiro 也没有强制要求任何规范,甚至没有很多依赖项。

强力支持 Web:Shiro 具有出色的 Web 应用程序支持,可以基于应用程序 URL 和 Web 协议(例如 REST)创建灵活的安全策略,同时还提供一组 JSP 库来控制页面输出。

兼容性强:Shiro 的设计模式使其易于与其他框架和应用程序集成。Shiro 与 Spring、Grails、Wicket、Tapestry、Mule、Apache Camel、Vaadin 等框架无缝集成。

看那么多字是不是都很恶心,总结起来就一个字,好用!

spirng security

​ 其实提到安全框架的话,还有一个耳熟能详的框架,就是spring系列的spring security,那这俩有什么区别呢?

  1. spring security是基于spring的,对spring有一定的依赖性,不过当前的话,大部分互联网项目都是基于spring的,所以这个也不能算缺点
  2. spring security功能比shiro更丰富一些,例如安全维护方面
  3. spring security的使用比起shiro来较为复杂

学习方式

​ 在我看来学习任何东西只要掌握其原理和运行流程,其实编码也就好说了,最多也就看看源码之类的东西,知道哪个类是干嘛的,都🆗的,而学习这些东西最好的地方就是官网啦,这里是shiro的官网,里面有更加详尽的介绍及使用,如果有什么问题,里面应该都有解决方案

learning

基本功能及简介

​ 下面就来看看shiro的基本功能吧,以图的方式来展示(摘自apache shiro官网):
在这里插入图片描述

功能介绍:

  1. Authentication:身份认证/登录,验证用户是不是拥有相应的身份
  2. Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限
  3. Session Manager:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通 JavaSE 环境,也可以是 Web 环境的;
  4. Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储
  5. Web Support:Web 支持,可以非常容易的集成到 Web 环境
  6. Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率
  7. Concurrency:Shiro 支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;
  8. Testing:提供测试支持
  9. Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问
  10. Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了

架构概述

​ 在最高概念层面上,Shiro的架构有3个主要概念:Subject、SecurityManager和Realms。下图是这些组件如何交互的高级概述(摘自apache shiro官网):
在这里插入图片描述

组件介绍:

  1. Subject:这里通常指与软件交互的任何东西,通常指用户

  2. SecurityManager:shiro架构的核心,所有和安全相关的操作都会与之交互,它管理所有的subject,类似于springmvc中的DispatcherServlet

  3. Realms:充当的是shiro和应用程序安全数据之间的桥梁,当需要实际与安全相关的数据(如用户帐户)进行交互以执行身份验证(登录)和授权(访问控制)时,Shiro 会从为应用程序配置的一个或多个 Realm 中查找其中的许多内容

    简单来说,可以把Realm看作是一个一个的特定的dao,它封装了数据源的连接细节,并根据需要提供数据给shiro,可以配置多个,但是至少提供一个Realm

详细架构

​ 下图显示了 Shiro 的核心架构概念以及每个概念的简短摘要(摘自apache shiro官网):

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-moiBv4d1-1669008965948)(assets/ShiroArchitecture.png)]

  • Subject( org.apache.shiro.subject.Subject ) 当前与软件交互的实体(用户、第 3 方服务、cron 作业等)的特定于安全的“视图”。
  • SecurityManager ( org.apache.shiro.mgt.SecurityManager ) 主要是用来协调其他组件顺利工作的
  • Authenticator ( org.apache.shiro.authc.Authenticator ) 负责Subject认证,可以自定义实现
    • Authentication Strategy ( org.apache.shiro.authc.pam.AuthenticationStrategy )是身份认证策略,当定义了多个Realm,它就可以去使用指定的策略去进行认证
  • Authorizer ( org.apache.shiro.authz.Authorizer )负责访问控制,是最终决定是否允许用户做某事的机制
  • SessionManager ( org.apache.shiro.session.mgt.SessionManager )负责管理session生命周期,不仅可以用在web环境
    • SessionDAO ( org.apache.shiro.session.mgt.eis.SessionDAO ) 负责代表SessionManager执行增删改查操作,这允许任何数据插入会话管理基础结构
  • CacheManager ( org.apache.shiro.cache.CacheManager )负责创建和管理其他shiro组件使用的缓存实例的生命周期
  • Cryptography ( org.apache.shiro.crypto.* )的中文释义是密码学,很自然的可以想到,安全框架肯定会包含加密模块,在数据方面进行加密
  • Realm( org.apache.shiro.realm.Realm )就没什么好说的了,和上面的意思一样,充当的是shiro和应用程序安全数据之间的桥梁

术语

  • 身份:验证身份是验证用户身份的过程

  • 授权:也称为访问控制,是确定用户是否被允许做某件事的过程

  • 凭证:是验证用户身份的一条信息,只有用户自己知道

  • 权限:至少在 Shiro 的解释中,权限是一种描述应用程序中原始功能的声明,仅此而已。权限是安全策略中最低级别的结构。它们仅定义应用程序可以做什么。他们没有描述“谁”能够执行这些操作。许可只是一种行为声明,仅此而已。

  • 主体(Subject):访问应用的用户,在 Shiro 中使用 Subject 代表该用户。用户只 有授权 后才允许访问相应的资源。

  • 角色(Role):权限的集合,一般情况下会赋予用户角色而不是权限,即这样用户可以拥有一组权限,赋予权限时比较方便。

基本使用

登录认证

流程:

  1. 收集用户身份和凭证,即用户名和密码
  2. 调用subject.login进行登录,如果失败则报异常AuthenticationException
  3. 创建自定义的Realm类,继承org.apache.shiro.realm.AuthenticatingRealm类,实现doGetAuthenticationInfo()方法

身份认证

流程:

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

角色授权

流程:

  1. 首先调用Subject.isPermitted/hasRole接口,其会委托给SecurityManager,而 SecurityManager接着会委托给 Authorizer
  2. Authorizer是真正的授权者,如果调用如isPermitted(“user:view”),其首先会让PermissionResolver把字符串转换成相应的Permission实例
  3. 在进行授权之前,其会调用相应的Realm获取Subject相应的角色/权限用于匹配传入的角色/权限
  4. Authorizer会判断Realm的角色/权限是否和传入的匹配,如果有多个Realm,会委托给ModularRealmAuthorizer进行循环判断,如果匹配如isPermitted/hasRole 会返回 true,否则返回false表示授权失败

实例

  • pom文件
<dependencies>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.9.0</version>
    </dependency>
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>
</dependencies>

​ shiro获取权限相关信息可以通过数据库获取,也可以通过shiro.ini文件获取,此处使用后者实现基本演示

  • shiro.ini
# 提供了对根对象 securityManager 及其依赖的配置
[main]
md5CredentialsMatcher = org.apache.shiro.authc.credential.Md5CredentialsMatcher
md5CredentialsMatcher.hashIterations = 3
myrealm = gyl.top.MyRealm
myrealm.credentialsMatcher = $md5CredentialsMatcher
securityManager.realms = $myrealm
# 提供了对用户/密码及其角色的配置,用户名=密码,角色 1,角色 2
[users]
zhangsan = 7174f64b13022acd3c56e2781e098a5f,role1,role2
lisi = l4
# 提供了角色及权限之间关系的配置,角色=权限 1,权限 2
[roles]
role1 = user:insert,user:select
# 这里还有一种叫urls,不过这里并未配置,它主要用来对url拦截相关的配置,
# 想更多了解shiro.ini配置文件
# 可以参考https://blog.csdn.net/u011781521/article/details/74892074
  • 自定义的Realm:这里其实使用了shiro加密的认证方式,在下面的小节中会提到
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.util.ByteSource;

/**
 * @author GYL
 * @version V1.0
 */
public class MyRealm extends AuthenticatingRealm {

    /**
     * 自定义登录认证方法,shiro的login方法底层会调用该类的认证方法进行认证
     * 需要配置自定义的realm生效,在ini文件中可以配置,或者在springboot中进行配置
     * 该方法只是获取进行对比的信息,认证逻辑还是安装shiro底层认证逻辑完成
     *
     * @param authenticationToken :获取登录信息
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 获取身份信息
        String principal = authenticationToken.getPrincipal().toString();
        // 获取凭证信息
        String password = authenticationToken.getCredentials().toString();
        System.out.println("认证信息:" + principal);
        System.out.println("凭证信息:" + password);
        // 访问数据库,获取数据库中存储的数据信息
        if ("zhangsan".equals(principal)) {
            // 数据库中存储着加盐三次迭代的密码
            String passwordInfo = "7174f64b13022acd3c56e2781e098a5f";
            // 创建封装校验逻辑的对象,把数据封装进去,然后返回
            return new SimpleAuthenticationInfo(
                    authenticationToken.getPrincipal(),
                    passwordInfo,
                    ByteSource.Util.bytes("salt"),
                    principal
            );
        }
        return null;
    }
}
  • 测试类
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;

/**
 * @author GYL
 * @version V1.0
 */
public class ShiroTest {
    public static void main(String[] args) {
        // 初始化获取SecurityManager
        IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager manager = factory.getInstance();
        SecurityUtils.setSecurityManager(manager);
        // 获取Subject对象
        Subject subject = SecurityUtils.getSubject();
        // 创建token对象,web应用用户名密码从页面传递
        AuthenticationToken token = new UsernamePasswordToken("zhangsan", "z3");
        // 调用login方法进行登录认证
        try {
            subject.login(token);
            System.out.println("登录成功");
            if (subject.hasRole("role1")) {
                System.out.println("有相关角色");
            }
            if (subject.isPermitted("user:insert")) {
                System.out.println("有相关权限");
            }
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            System.out.println("用户不存在");
        } catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            System.out.println("密码错误");
        } catch (AuthenticationException ae) {
            //unexpected condition? error?
        }
    }
}

shiro加密

​ 在开发中,常会对一些敏感数据进行加密,比如用户的密码等信息

import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.crypto.hash.SimpleHash;

/**
 * @author GYL
 * @version V1.0
 */
public class ShiroMd5 {
    public static void main(String[] args) {
        // 密码明文:
        String password = "z3";
        // 使用md5加密
        Md5Hash md5Hash = new Md5Hash(password);
        System.out.println(md5Hash);
        // 带盐的md5加密,盐就是在密码明文后拼接新字符串,然后再进行加密
        Md5Hash md5Hash1 = new Md5Hash(password, "salt");
        System.out.println(md5Hash1);
        // 为了保证安全,避免被破解还可以多次迭代加密,保证数据安全
        Md5Hash md5Hash2 = new Md5Hash(password, "salt", 3);
        System.out.println(md5Hash2);
        // 使用父类实现加密
        SimpleHash simpleHash = new SimpleHash("MD5", password, "salt", 3);
        System.out.println(simpleHash);

    }
}
  • 有关shiro的基本介绍和使用就到这里,本文章参考了尚硅谷shiro讲解及shiro官方文档

每一点滴的进展,都是缓慢而艰苦的

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值