zoukankan      html  css  js  c++  java
  • 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("用户未授权!");
            }
    
    
        }
    
    }
  • 相关阅读:
    govalidator----结构体tag验证
    结构字段验证--validator.v9
    序列化
    案例:8,64,256都是2的阶次方数(8是2的3次方),用Java编写程序来判断一个整数是不是2的阶次方数。
    易错点
    什么是线程与进程?
    对象与实例的区别?
    什么情况下用断言?assert
    垃圾收集器什么时候回收垃圾?
    HashMap 和 HashTable 的区别
  • 原文地址:https://www.cnblogs.com/StarChen20/p/14004045.html
Copyright © 2011-2022 走看看