shiro-----shiro入门

Shiro简介

1、什么是Shiro

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

官方文档:Apache Shiro Architecture | Apache Shiro

2、Shiro核心架构

Subject
Subject即主体,外部应用与subject进行交互,subject记录了当前的操作用户,将用户的概念理解为当前操作的主体。外部程序通过subject进行认证授权,而subject是通过SecurityManager安全管理器进行认证授权

SecurityManager
SecurityManager即安全管理器,对全部的subject进行安全管理,它是shiro的核心,负责对所有的subject进行安全管理。通过SecurityManager可以完成subject的认证、授权等,实质上SecurityManager是通过Authenticator进行认证,通过Authorizer进行授权,通过SessionManager进行会话管理等

SecurityManager是一个接口,继承了Authenticator, Authorizer, SessionManager这三个接口

Authenticator
Authenticator即认证器,对用户身份进行认证,Authenticator是一个接口,shiro提供ModularRealmAuthenticator实现类,通过ModularRealmAuthenticator基本上可以满足大多数需求,也可以自定义认证器

Authorizer
Authorizer即授权器,用户通过认证器认证通过,在访问功能时需要通过授权器判断用户是否有此功能的操作权限

Realm
Realm即领域,相当于datasource数据源,securityManager进行安全认证需要通过Realm获取用户权限数据,比如:如果用户身份数据在数据库那么realm就需要从数据库获取用户身份信息

不要把realm理解成只是从数据源取数据,在realm中还有认证授权校验的相关的代码

SessionManager
sessionManager即会话管理,shiro框架定义了一套会话管理,它不依赖web容器的session,所以shiro可以使用在非web应用上,也可以将分布式应用的会话集中在一点管理,此特性可使它实现单点登录

SessionDAO
SessionDAO即会话dao,是对session会话操作的一套接口,比如要将session存储到数据库,可以通过jdbc将会话存储到数据库

CacheManager
CacheManager即缓存管理,将用户权限数据存储在缓存,这样可以提高性能

Cryptography
Cryptography即密码管理,shiro提供了一套加密/解密的组件,方便开发。比如提供常用的散列、加/解密等功能。
 


在应用程序角度来观察如何使用Shiro完成工作

Subject:主体,代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等;即一个抽象概念;所有Subject 都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager;可以把Subject认为是一个门面;SecurityManager才是实际的执行者;
   

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

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



组件之间的关系

shiro运行流程

  • 首先调用 Subject.login(token) 进行登录,其会自动委托给 Security Manager,调用之前必须通过 SecurityUtils.setSecurityManager() 设置;

  • SecurityManager 负责真正的身份验证逻辑;它会委托给 Authenticator 进行身份验证;

  • Authenticator 才是真正的身份验证者,Shiro API 中核心的身份认证入口点,此处可以自定义插入自己的实现;

  • Authenticator 可能会委托给相应的 AuthenticationStrategy 进行多 Realm 身份验证,默认 ModularRealmAuthenticator 会调用 AuthenticationStrategy 进行多 Realm 身份验证;

  • Authenticator 会把相应的 token 传入 Realm,从 Realm 获取身份验证信息,如果没有返回 / 抛出异常表示身份验证失败了。此处可以配置多个 Realm,将按照相应的顺序及策略进行访问。

shiro认证

身份认证

创建一个普通的maven项目,引入shiro的依赖

<!--shiro-->
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-core</artifactId>
      <version>${shiro.version}</version>
    </dependency>

    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-web</artifactId>
      <version>${shiro.version}</version>
    </dependency>

    <!-- **********************  日志配置  ********************** -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>${slf4j.version}</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>jcl-over-slf4j</artifactId>
      <version>${slf4j.version}</version>
      <scope>runtime</scope>
      <exclusions>
        <exclusion>
          <artifactId>slf4j-api</artifactId>
          <groupId>org.slf4j</groupId>
        </exclusion>
      </exclusions>
    </dependency>
    <!--2) 用于与slf4j保持桥接-->
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-slf4j-impl</artifactId>
      <version>${log4j2.version}</version>
      <exclusions>
        <exclusion>
          <artifactId>slf4j-api</artifactId>
          <groupId>org.slf4j</groupId>
        </exclusion>
      </exclusions>
    </dependency>
    <!--3) 核心log4j2jar包-->
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-api</artifactId>
      <version>${log4j2.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-core</artifactId>
      <version>${log4j2.version}</version>
    </dependency>
    <!--4) web工程需要包含log4j-web,非web工程不需要-->
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-web</artifactId>
      <version>${log4j2.version}</version>
      <scope>runtime</scope>
    </dependency>
    <!--5) 需要使用log4j2的AsyncLogger需要包含disruptor-->
    <dependency>
      <groupId>com.lmax</groupId>
      <artifactId>disruptor</artifactId>
      <version>${log4j2.disruptor.version}</version>
    </dependency>

创建shiro配置文件shiro-users.ini

[users]
zs=123
ls=123
admin=123

shiro的配置文件是一个.ini文件,类似于.txt文件

.ini文件经常用作某些软件的特定的配置文件,可以支持一些复杂的数据格式,shiro可以按照内部约定的某种格式读取配置文件中的数据

之所以提供这个配置文件是用来学习shiro时书写我们系统中相关的权限数据,从而减轻配置数据库并从数据库读取数据的压力,降低学习成本,提高学习效率

测试Java代码

    public static void main(String[] args)throws Exception {
        //1、创建SecurityManagerFactory,用于读取加载安全的数据源
        IniSecurityManagerFactory factory
                = new IniSecurityManagerFactory("classpath:shiro-permission.ini");
        
        //2、创建安全管理器SecurityManager
        SecurityManager securityManager = factory.getInstance();
        
        //3、将SecurityManager交由SecurityUtils来管理
        SecurityUtils.setSecurityManager(securityManager);
        
        //4、创建Subject主体
        Subject subject = SecurityUtils.getSubject();
       
        //5、创建账号密码登录方式的令牌Token
        UsernamePasswordToken token = new UsernamePasswordToken("admin","123");
        
        //6、用户认证(shiro的核心功能之一)
        subject.login(token);
        System.out.println("用户认证成功!");

        //7、安全推出
        subject.logout();
    }

角色认证

创建shiro配置文件shiro-role.ini

[users]
zs=123,role1
ls=123,role2
admin=123,role1,role2

 测试Java代码

public static void main(String[] args)throws Exception {
        //1、创建SecurityManagerFactory,用于读取加载安全的数据源
        IniSecurityManagerFactory factory
                = new IniSecurityManagerFactory("classpath:shiro-role.ini");
        //2、创建安全管理器SecurityManager
        SecurityManager securityManager = factory.getInstance();
        //3、将SecurityManager交由SecurityUtils来管理
        SecurityUtils.setSecurityManager(securityManager);
        //4、创建Subject主体
        Subject subject = SecurityUtils.getSubject();
        //5、创建账号密码登录方式的令牌Token
        /**
         *org.apache.shiro.authc.UnknownAccountException 账号错误异常
         *org.apache.shiro.authc.IncorrectCredentialsException 密码错误异常
         * org.apache.shiro.authz.UnauthorizedException 授权错误异常
         */
        UsernamePasswordToken token = new UsernamePasswordToken("admin","123");
        //6、用户认证(shiro的核心功能之一)
        subject.login(token);
        System.out.println("用户认证成功!");


        //8、角色认证
        第一种方式:
        if (subject.hasRole("role12")) {
            System.out.println("角色验证成功!");
        } else {
            System.out.println("角色验证失败!");
        }
        
        第二种方式:
        subject.checkRole("role2");
        System.out.println("角色验证成功!");


        //7、安全推出
        subject.logout();
    }

权限验证

创建shiro配置文件shiro-permission.ini

[users]
zs=123,role1
ls=123,role2
admin=123,role1,role2,role4

[roles]
role1=system:user:add
role2=system:user:add,system:user:select
role3=system:user:add,system:user:select,system:user:update,system:user:delete
role4=system:*:*

 测试Java代码

public static void main(String[] args)throws Exception {
        //1、创建SecurityManagerFactory,用于读取加载安全的数据源
        IniSecurityManagerFactory factory
                = new IniSecurityManagerFactory("classpath:shiro-permission.ini");
        //2、创建安全管理器SecurityManager
        SecurityManager securityManager = factory.getInstance();
        //3、将SecurityManager交由SecurityUtils来管理
        SecurityUtils.setSecurityManager(securityManager);
        //4、创建Subject主体
        Subject subject = SecurityUtils.getSubject();
        //5、创建账号密码登录方式的令牌Token
        /**
         *org.apache.shiro.authc.UnknownAccountException 账号错误异常
         *org.apache.shiro.authc.IncorrectCredentialsException 密码错误异常
         * org.apache.shiro.authz.UnauthorizedException 授权错误异常
         */
        UsernamePasswordToken token = new UsernamePasswordToken("admin","123");
        //6、用户认证(shiro的核心功能之一)
        subject.login(token);
        System.out.println("用户认证成功!");


        //8、角色认证
       

        subject.checkRole("role2");
        System.out.println("角色验证成功!");


        //9、权限验证
        第一种方式:
        if (subject.isPermitted("system:user:add")) {
            System.out.println("权限验证成功!");
        } else {
            System.out.println("权限验证失败!");
        }

        第二种方式:
        subject.checkPermission("system:w:wd");
        System.out.println("权限验证成功!");

        //7、安全推出
        subject.logout();
    }

认证的几种状态

UnknownAccountException:用户名错误

IncorrectCredentialsException:密码错误

DisabledAccountException:账号被禁用

LockedAccountException:账号被锁定

ExcessiveAttemptsException:登录失败次数过多

ExpiredCredentialsException:凭证过期
 

shiro集成web(shiro-web.ini)

配置shiro-web.ini文件

[main]
#定义身份认证失败后的请求url映射,loginUrl是身份认证过滤器中的一个属性
authc.loginUrl=/login.do
#定义角色认证失败后的请求url映射,unauthorizedUrl是角色认证过滤器中的一个属性
roles.unauthorizedUrl=/unauthorized.jsp
#定义权限认证失败后请求url映射,unauthorizedUrl是角色认证过滤器中的一个属性
perms.unauthorizedUrl=/unauthorized.jsp

[users]
zs=123,role1
ls=123,role2
ww=123,role3
zdm=123,admin


[roles]
role1=user:create
role2=user:create,user:update
role3=user:create,user:update,user:delete,user:view,user:load
admin=user:*

配置web.xml

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         id="WebApp_ID" version="3.0">
  <display-name>Archetype Created Web Application</display-name>

  <!--实现web项目于shiro集成配置 并完成shiro的初始化工作(加载读取shiro-web.ini)-->
  <context-param>
    <param-name>shiroConfigLocations</param-name>
    <param-value>classpath:shiro-web.ini</param-value>
  </context-param>
  <listener>
    <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
  </listener>

  <!--配置shiro核心过滤器,用于过滤请求-->
  <filter>
    <filter-name>ShiroFilter</filter-name>
    <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>ShiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  
  
  <!--配置欢迎页-->
  <welcome-file-list>
    <welcome-file>login.jsp</welcome-file>
  </welcome-file-list>
</web-app>

Servlert

@WebServlet("/login.do")
public class LoginSevlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取前端传入的账号密码
        String username = req.getParameter("username");
        String password = req.getParameter("password");

        //根据账号密码创建登录令牌
        UsernamePasswordToken user = new UsernamePasswordToken(username, password);

        //获取主题Subject
        Subject subject = SecurityUtils.getSubject();

        try {
            //进行用户身份验证
            subject.login(user);
            //将账号信息保存到session中
            req.getSession().setAttribute("username",username);
            //重定向到主页面
            resp.sendRedirect(req.getContextPath()+"/main.jsp");
        } catch (Exception e) {
            req.setAttribute("message","账号或密码错误");
            req.getRequestDispatcher("/login.jsp").forward(req,resp);
            e.printStackTrace();
        }

    }
}
@WebServlet("/logout.do")
public class LogoutServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取主题Subject
        Subject subject = SecurityUtils.getSubject();
        //安全退出
        subject.logout();
        //重定向到登录页面
        resp.sendRedirect(req.getContextPath()+"/login.jsp");
    }
}

测试:

在未登录的下去访问

http://localhost:8080/shiro01/user/updatePwd.jsp

在登录zs用户

只能看到如下功能

 

 在点击用户新增功能

 登录zdm管理员账号

 所有的权限均可操作

代码地址 提取码:lhne

至此,shiro入门介绍完毕,由于作者水平有限难免有疏漏,欢迎留言纠错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值