Shiro(Java权限框架)入门

什么是Shiro?

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

shiro不依赖于spring,shiro不仅可以实现 web应用的权限管理,还可以实现c/s系统,分布式系统权限管理,shiro属于轻量框架,越来越多企业项目开始使用shiro。

Shiro组成部分

  • subject:主体,可以是用户也可以是程序,主体要访问系统,系统需要对主体进行认证、授权。
  • securityManager:安全管理器,主体进行认证和授权都是通过securityManager进行。securityManager是一个集合,真正做事的不是securityManager而是它里面的东西。
  • authenticator:认证器,主体进行认证最终通过authenticator进行的。
  • authorizer:授权器,主体进行授权最终通过authorizer进行的。
  • sessionManager:web应用中一般是用web容器(中间件tomcat)对session进行管理,shiro也提供一套session管理的方式。
  • shiro不仅仅可以用于web管理也可以用于cs管理,所以他不用web容器的session管理。
  • SessionDao: 通过SessionDao管理session数据,针对个性化的session数据存储需要使用sessionDao(如果用tomcat管理session就不用SessionDao,如果要分布式的统一管理session就要用到SessionDao)。
  • cache Manager:缓存管理器,主要对session和授权数据进行缓存(权限管理框架主要就是对认证和授权进行管理,session是在服务器缓存中的),比如将授权数据通过cacheManager进行缓存管理,和ehcache整合对缓存数据进行管理(redis是缓存框架)。
  • realm:域,领域,相当于数据源,通过realm存取认证、授权相关数据(原来是通过数据库取的)。注意:authenticator认证器和authorizer授权器调用realm中存储授权和认证的数据和逻辑。
  • cryptography:密码管理,比如md5加密,提供了一套加密/解密的组件,方便开发。比如提供常用的散列、加/解密等功能。比如 md5散列算法(md5只有加密没有解密)。

核心组件

在shiro中核心的概念有三个:

1.subject

即“当前操作用发户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程(比如微信QQ等等)、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。但考虑到大多数目的和用途,你可以把它认为是Shiro的“用户”概念。Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。

2.Security Manager

它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务,且它管理着所有Subject;可以看出它是Shiro 的核心,它负责与后边介绍的其他组件进行交互,如果学习过SpringMVC,你可以把它看成DispatcherServlet前端控制器。

3.Realm

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

  从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。

Shiro 特点

(1)易于理解的 Java Security API;
(2)简单的身份认证(登录),支持多种数据源(LDAP,JDBC,Kerberos,ActiveDirectory 等);
(3)对角色的简单的签权(访问控制),支持细粒度的签权;
(4)支持一级缓存,以提升应用程序的性能;
(5)内置的基于 POJO 企业会话管理,适用于 Web 以及非 Web 的环境;
(6)异构客户端会话访问;
(7)非常简单的加密 API,自带的加密API完全够用;
(8)不跟任何的框架或者容器捆绑,可以独立运行

实现简单案例

1.添加依赖:

        <!-- shiro核心包 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <!-- 添加shiro web支持 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>${shiro.version}</version>
        </dependency>

2.添加安全数据源shiro-permission.ini文件(官方推荐使用ini文件格式):

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


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

3.添加Demo测试类:

package com.star.demo;

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 java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Demo {

    public static void main(String[] args) {

        //org.apache.shiro.authc.IncorrectCredentialsException: Submitted credentials for token 密码错误认证失败
        //org.apache.shiro.authc.UnknownAccountException: Realm [org.apache.shiro...] was unable to find account data
        // 账户不存在错误

        //1:获取securityFactory工厂类
        IniSecurityManagerFactory iniSecurityManagerFactory = new IniSecurityManagerFactory("classpath:shiro" +
                "-permission" +
                ".ini");
        //2.获取安全管理器对象
        SecurityManager instance = iniSecurityManagerFactory.getInstance();
        //3.设置subjectManager对象,把subjec对象交给SecurityUtils管理
        SecurityUtils.setSecurityManager(instance);
        //4.获取subject对象
        Subject subject = SecurityUtils.getSubject();
        //5.生成token
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("admin","123");
        //6.进行验证
        try {
            //7.登陆(身份认证)
            subject.login(usernamePasswordToken);
            System.out.println("身份认证成功!");
        } catch (AuthenticationException e) {
            e.printStackTrace();
            System.out.println("身份认证失败!");
        }

        //8.用户授权
        try {
//            if(subject.hasRole("role6")){//1.普通授权方式,检查单个授权
            //2.传集合用户授权,有一个未授权的就返回false
//            List<String> list= new ArrayList<>();
//            list.add("role1");
//            list.add("role6");
//            list.add("role3");
//            if(subject.hasAllRoles(list)){//传集合判断权限
            //3.hasRoles方式判断权限
            boolean[] booleans = subject.hasRoles(Arrays.asList("role1", "role2", "role3"));
            boolean f = false;
            int n = 0;
            for (int i = booleans.length - 1; i >= 0; i--) {
                if(booleans[i])
                    ++n;
                if(n==booleans.length){
                    f = true;
                    break;
                }
            }
            if(f){
                System.out.println("用户授权成功!");
            }else {
                System.out.println("用户未授权!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        //9.check方式检查授权,未授权直接报错
        try {
            //1.checkRole方式不存在权限直接报错org.apache.shiro.authz.UnauthorizedException: Subject does not have role [role7]
//            subject.checkRole("role7");
            //2.checkRoles方式不存在直接报错,可以传可变的String参数或者是数组
            subject.checkRoles(Arrays.asList("role1","role2","role3"));
            subject.checkRoles("role1","role2","role3");
            System.out.println("用户已授权~");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("用户未授权!");
        }

        //10.permission方式检查权限
        try {
//            //isPermitted可以接受String可变参数,集合等
//            if(subject.isPermitted("user:*"))
//                System.out.println("用户已授权!");
//            else
//                System.out.println("用户未授权!");
            //checkPermitted方式(*代表所有权限不管权限是否存在)
            subject.checkPermission("user:234234");
            System.out.println("用户已授权!");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("用户未授权!");
        }


    }

}
posted @ 2020-11-19 10:36  _未来可期  阅读(571)  评论(0编辑  收藏  举报