Shiro基础入门

重点:

  • 1、Shiro简介;
  • 2、Shiro基本流程及组件;
  • 3、Shiro代码验证;

重点解析:

一、Shiro简介

1.1、什么是shiro
(1)、shiro是apache的一个开源框架,是一个权限管理的框架,实现 用户认证、用户授权。
(2)、 spring中有spring security (原名Acegi),是一个权限框架,它和spring依赖过于紧密,没有shiro使用简单。
(3)、 shiro不依赖于spring,shiro不仅可以实现 web应用的权限管理,还可以实现c/s系统, 分布式系统权限管理,shiro属于轻量框架,越来越多企业项目开始使用shiro。

1.2. 在应用程序角度来观察如何使用Shiro完成工作(如图)
在这里插入图片描述
Subject:主体,代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等;即一个抽象概念;所有Subject 都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager;可以把Subject认为是一个门面;SecurityManager才是实际的执行者;

SecurityManager:安全管理器;即所有与安全有关的操作都会与SecurityManager 交互;且它管理着所有Subject;可以看出它是Shiro 的核心,它负责与后边介绍的其他组件进行交互,如果学习过SpringMVC,你可以把它看成DispatcherServlet前端控制器;

Realm:域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。

二、Shiro基本流程及组件

1、Shiro基本流程

Shiro流程图:

Subject:主体,用来与用户交互的对象。它其实是一个门面对象,专门用于管理来自客户端的数据。比如客户端传来了一批帐号密码数据,它需要将这批数据传入Shiro的内部核心SecurityManager中,以验证帐号密码是否正确。再比如,判断当前用户是否有相关的角色,它会去问问内部的SecurityManager,这个人是“小学生角色”吗?

你懂的理解就是:Subject就是一个拉客滴,它知道本会所提供的所有服务。来了一批客人,它需要将客人引进到SecurityManager中进行服务,所以说SecurityManager是shiro底层的核心。

SecurityManager:安全中心,它相当于“用户信息”与“数据源”的中间者。用户信息指用户在WEB页面上输入的数据,通常指 用户名、邮箱、密码、手机号等。 “数据源”指数据库中存放的数据。 SecurityManager的作用就是把“用户信息”拿去与“数据源”比对,看“用户信息”是不是存在于“数据源”中。

Realm:数据源。Shiro从数据库中查询一些数据,保存在Realm这种对象中。Shiro会把从Subject中获取的数据与Realm的数据进行对比,从而确定客户端传来的帐号密码是否正确。

流程如下:
步骤一:Shiro把用户的数据封装成标识token,token一般封装着用户名,密码等信息。

步骤二:使用Subject门面获取到封装着用户的数据的标识token

步骤三:Subject把标识token交给SecurityManager,在SecurityManager安全中心中,SecurityManager把标识token委托给认证器Authenticator进行身份验证。认证器的作用一般是用来指定如何验证,它规定本次认证用到哪些Realm。

步骤四:认证器Authenticator将传入的标识token,与数据源Realm对比,验证token是否合法。

从代码的层面来理解: Subject对象其实是一个门面类,它能够执行非常多的操作,例如认证授权用户退出。但是它实际上将这些操作委托给内部的SecurityManager去做。简单点说,Subject的底层实现就是SecurityManager。

    public class Subject ...

               private SecurityManager  securityManager;

               public  void  login() {
                 securityManager. login() ; 
                 }

2、Shiro基础组件及架构
Shiro可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE环境,也可以用在JavaEE环境。Shiro可以帮助我们完成:认证、授权、加密、会话管理、与Web集成、缓存等。这不就是我们想要的嘛,而且Shiro的API也是非常简单;其基本功能点如下图所示:
在这里插入图片描述

Authentication:身份认证/登录,验证用户是不是拥有相应的身份;

Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;

Session Manager:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的;

Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;

Web Support:Web支持,可以非常容易的集成到Web环境;

Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率;

Concurrency:shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;

Testing:提供测试支持;

Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;

Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。

记住一点,Shiro不会去维护用户、维护权限;这些需要我们自己去设计/提供;然后通过相应的接口注入给Shiro即可。

接下来我们分别从外部和内部来看看Shiro的架构,对于一个好的框架,从外部来看应该具有非常简单易于使用的API,且API契约明确;从内部来看的话,其应该有一个可扩展的架构,即非常容易插入用户自定义实现,因为任何框架都不能满足所有需求。

也就是说对于我们而言,最简单的一个Shiro应用:

1、应用代码通过Subject来进行认证和授权,而Subject又委托给SecurityManager;

2、我们需要给Shiro的SecurityManager注入Realm,从而让SecurityManager能得到合法的用户及其权限进行判断。

从以上也可以看出,Shiro不提供维护用户/权限,而是通过Realm让开发人员自己注入。

接下来我们来从Shiro内部来看下Shiro的架构,如下图所示:

在这里插入图片描述

Subject:主体,可以看到主体可以是任何可以与应用交互的“用户”;

SecurityManager:相当于SpringMVC中的DispatcherServlet或者Struts2中的FilterDispatcher;是Shiro的心脏;所有具体的交互都通过SecurityManager进行控制;它管理着所有Subject、且负责进行认证和授权、及会话、缓存的管理。

Authenticator:认证器,负责主体认证的,这是一个扩展点,如果用户觉得Shiro默认的不好,可以自定义实现;其需要认证策略(Authentication Strategy),即什么情况下算用户认证通过了;

Authrizer:授权器,或者访问控制器,用来决定主体是否有权限进行相应的操作;即控制着用户能访问应用中的哪些功能;

Realm:可以有1个或多个Realm,可以认为是安全实体数据源,即用于获取安全实体的;可以是JDBC实现,也可以是LDAP实现,或者内存实现等等;由用户提供;注意:Shiro不知道你的用户/权限存储在哪及以何种格式存储;所以我们一般在应用中都需要实现自己的Realm;

SessionManager:如果写过Servlet就应该知道Session的概念,Session呢需要有人去管理它的生命周期,这个组件就是SessionManager;而Shiro并不仅仅可以用在Web环境,也可以用在如普通的JavaSE环境、EJB等环境;所有呢,Shiro就抽象了一个自己的Session来管理主体与应用之间交互的数据;这样的话,比如我们在Web环境用,刚开始是一台Web服务器;接着又上了台EJB服务器;这时想把两台服务器的会话数据放到一个地方,这个时候就可以实现自己的分布式会话(如把数据放到Memcached服务器);

SessionDAO:DAO大家都用过,数据访问对象,用于会话的CRUD,比如我们想把Session保存到数据库,那么可以实现自己的SessionDAO,通过如JDBC写到数据库;比如想把Session放到Memcached中,可以实现自己的Memcached SessionDAO;另外SessionDAO中可以使用Cache进行缓存,以提高性能;

CacheManager:缓存控制器,来管理如用户、角色、权限等的缓存的;因为这些数据基本上很少去改变,放到缓存中后可以提高访问的性能

Cryptography:密码模块,Shiro提高了一些常见的加密组件用于如密码加密/解密的。

三、代码验证

首先导入shiro的依赖。

<dependencies>  
    <dependency>  
        <groupId>junit</groupId>  
        <artifactId>junit</artifactId>  
        <version>4.9</version>  
    </dependency>  
    <dependency>  
        <groupId>commons-logging</groupId>  
        <artifactId>commons-logging</artifactId>  
        <version>1.1.3</version>  
    </dependency>  
    <dependency>  
        <groupId>org.apache.shiro</groupId>  
        <artifactId>shiro-core</artifactId>  
        <version>1.2.2</version>  
    </dependency>  
</dependencies> 

编写Junit测试用例

public class MyFirstTest {
    @Test
    public void test1() {
        //读取配置文件,相当于在加载数据源
        Factory<org.apache.shiro.mgt.SecurityManager> factory = 
                           new IniSecurityManagerFactory("classpath:shiro_1.ini");
        //SecurityManager 是Shiro内部的底层实现,几乎所有功能都由其实现
        org.apache.shiro.mgt.SecurityManager sm = factory.getInstance();
        //SecurityUtils是一个工具,方便用户调用,它封装了SecurityManager 
        SecurityUtils.setSecurityManager(sm);
        //生成一个SecurityManager的门面类,即Subject。
        Subject subject = SecurityUtils.getSubject();
        //封装用户的数据
        UsernamePasswordToken token = new UsernamePasswordToken("jay", "123");
        //Subject接收到的方法参数,最终将会传到SecurityManager中进行验证
        //将用户的数据token 最终传递到Realm中进行对比
        subject.login(token);
        //判断本帐号是否已经被认证
        Assert.assertEquals(true, subject.isAuthenticated());
    }
}

– 帐号/密码认证
4. Shiro身份验证(shiro.ini)
https://www.w3cschool.cn/shiro/andc1if0.html

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

ps:

1、Shiro权限认证(支持三种方式的授权)
1.1 编程式:通过写if/else授权代码块完成

  Subject subject = SecurityUtils.getSubject();
  if(subject.hasRole("admin")) {
    //有权限
  } else {
    //无权限
  }

1.2 注解式:通过在执行的Java方法上放置相应的注解完成,另外,没有权限将抛出相应的异常

@RequiresRoles("admin")
  public void hello() {
    //有权限
  }

1.3 JSP/GSP标签:在JSP/GSP页面通过相应的标签完成

<shiro:hasRole name="admin">
      <!— 有权限 —>
      </shiro:hasRole>
  1. 授权
    2.1 基于角色的访问控制(shiro-role.ini|粗颗粒度)
    规则:“用户名=密码,角色1,角色2”
    方法: hasRole/hasRoles/hasAllRoles和checkRole/checkRoles

    注1:hasXxx和checkXxx区别,hasXxx会返回boolean类型的数据,用来判断,而checkXxx不会返回任何东西,
    如果验证成功就继续处理下面的代码,否则会抛出一个异常UnauthorizedException

2.2 基于资源的访问控制(shiro-permission.ini|细颗粒度)
即:首先根据用户名找到角色,然后根据角色再找到权限
规则1:“用户名=密码,角色1,角色2”
规则2:“角色=权限1,权限2”
规则3:“资源标识符:操作:对象实例ID” 即对哪个资源的哪个实例可以进行什么操作
注:每个部分可以不填写,默认就是*
user::
tea::
stu::

  方法: isPermitted/checkPermissions   

  注1:permission:许可,权限
  注2:create,update,delete,view这些是可以自行定义的
  1. shiro集成web(shiro-web.ini)

<%@taglib prefix=“r” uri=“http://shiro.apache.org/tags” %>

3.1 配置shiro-web.ini文件

3.2 通过监听器EnvironmentLoaderListener读取配置文件,来创建相应的WebEnvironment

  注1:可通过shiroConfigLocations参数,指定shiro的配置文件
  注2:shiroConfigLocations 默认是“/WEB-INF/shiro.ini”,IniWebEnvironment默认是先从/ WEB-INF/shiro.ini加载,
       如果没有就默认加载 classpath:shiro.ini。

3.3 配置过滤器ShiroFilter

  注1:放在web.xml文件的最前面

3.4 开发中不断修改配置文件

  1. 其它
    4.1 不足之处

    1. 用户名/密码硬编码在ini配置文件,以后需要改成如数据库存储,且密码需要加密存储;
    2. 用户身份Token可能不仅仅是用户名/密码,也可能还有其他的,如登录时允许用户名/邮箱/手机号同时登录。
      4.2 JUnit4:Test注解的两个属性:expected和timeout
      expected属性:用来指示期望抛出的异常类型,抛出指定的异常类型,则测试通过 。
      timeout属性:用来指示时间上限,当测试方法的时间超过这个时间值时测试就会失败(注意超时了报的是Errors,如果是值错了是Failures)
  2. 配置文件
    xml
    properties
    ini
    [node]
    key=value

猜你喜欢

转载自blog.csdn.net/cao_2000/article/details/85321438