Apache_Shrio


一、pandas是什么?

官网
参考文档

Apache Shiro™是一个功能强大且易于使用的 Java 安全框架,它执行身份验证、授权、加密和会话管理。借助 Shiro 易于理解的 API,您可以快速轻松地保护任何应用程序——从最小的移动应用程序到最大的 Web 和企业应用程序。

二、Shrio的特点

机反

  • 易于使用: 易于使用是该项目的最终目标,。应用程序安全性可能非常令人困惑和沮丧,并被视为“必要的邪恶”。如果您使它易于使用,以使新手程序员可以开始使用它,那么就不必再痛苦了。
  • 全面:shrio的应用广泛 ,他几乎可以满足你的全部需求
  • 灵活: shiro 可以在任何的应用程序环境中使用 ,而且没有强制要求的任何规范,甚至依赖也非常的少
  • 具有web功能: 具有非常优秀的web应用程序支持,允许您基于应用程序URl和web协议(列如REST)创建灵活的安全策略,同时还提供一组jsp库来控制页面输出
  • 可插拔: Shiro干净的API和设计模式使它易于与许多其他框架和应用程序集成。您会看到Shiro与Spring,Grails,Wicket,Tapestry,Mule,Apache Camel,Vaadin等框架无缝集成。
  • 阿帕奇: Apache Shiro是Apache Software Foundation(Apache软件基金会)的一部分,该组织被证明以其社区的最大利益行事。项目开发和用户群体友好的公民随时可以提供帮助。如果需要,像Katasoft这样的商业公司也可以提供专业的支持和服务。

三、核心架构

官网
在这里插入图片描述

1.Subject

Subject一词是一个安全术语,基本上表示“当前正在执行的用户”。它只是意味着“当前正在与软件交互的东西”。
它只是不被称为“用户”,因为“用户”一词通常与人类相关联。在安全的世界,术语“主题”可以指一个人,但也有会谈进程,守护进程帐户,或任何类似。

  import org.apache.shiro.subject.Subject;	     
  import org.apache.shiro.SecurityUtils;             
  Subject currentUser = SecurityUtils.getSubject();

2.SecurityManager

主题的“幕后”对应对象是SecurityManager。主题代表当前用户的安全操作,而SecurityManager管理所有用户的安全操作。它是Shiro体系结构的核心,并充当一种“伞”对象,引用了许多内部嵌套的安全组件,这些安全组件构成了一个对象图。它管理着所有 Subject、且负责进行认证和授权、及会话、缓存的管理。每个应用程序几乎总是有一个SecurityManager实例。它本质上是一个应用程序单例(尽管不必是静态单例)普通的Java代码,Spring XML,YAML,.properties和.ini文件等进行配置

3.Realms

Realms充当Shiro与应用程序的安全数据之间的“桥梁”或“连接器”,也就是说,当需要真正与安全性相关的数据(例如用户帐户)进行交互以执行身份验证(登录)和授权(访问控制)时,Shiro会从为应用程序配置的一个或多个Realms中查找其中的许多内容。本质上是特定于安全性的DAO:它封装了数据源的连接详细信息,并根据需要使关联数据可用于Shiro。

4.认证Authentication

身份验证是验证用户身份的过程。也就是说,当用户通过应用程序进行身份验证时,他们在证明自己实际上就是他们所说的身份。有时也称为“登录”。这通常是一个三步过程。

  1. 收集用户的标识信息(称为主体 用户名)和支持身份的凭证(称为凭据 密码)。
AuthenticationToken token = new UsernamePasswordToken(username, password);
  1. 将主体和凭据提交到系统。
Subject currentUser = SecurityUtils.getSubject();	
currentUser.login(token);
  1. 如果提交的凭据与系统对该用户身份的期望匹配,则认为该用户已通过身份验证。如果它们不匹配,则不认为用户已通过身份验证。
try {   
 currentUser.login(token);    
 //通过身份验证,执行其他业务} 
 catch (IncorrectCredentialsException ice) {       
  //密码错误
  } catch (LockedAccountException lae) {      
   //账户锁定(默认系统不提供,可以编写代码过程中自己实现}
 //许多其他异常
   catch (AuthenticationException ae) {  
     //上面配置的异常的父类
   } 

5.授权authorization

授权本质上是访问控制-控制用户可以在应用程序中访问的内容(例如资源,网页等)。大多数用户通过使用角色和权限等概念来执行访问控制。也就是说,通常根据分配给他们的角色和/或权限,允许用户执行某项操作或不执行某项操作。
判断角色

判断角色:	
if ( subject.hasRole(“administrator”) ) {
	    //show the ‘Create User’ button	
	    } else {	    
	    //grey-out the button?	
	    } 

判断权限

if ( subject.isPermitted(“user:create”) ) {    
//show the ‘Create User’ button
} else {    
//grey-out the button?
} 

四、示例

示例1.

  1. 创建基础maven项目 引入jar包
   <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core -->
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-core</artifactId>
      <version>1.8.0</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.0.4</version>
    </dependency>
  1. 创建ini文件 初始化文件
#用户对象
[users]
#用户名密码 ,拥有的角色 可以配置多个
admin=123456,role2,role3,伊拉克
scott=tiger,role1
smith=tiger,role2
#角色
[roles]
#角色role1对用户有create,update权限
role1=user:create,user:update
#角色role2对用户有 create ,delete权限
role2=user:create,user:delete
#角色role3对用户有create权限
role3=user:create
#添加的新角色 角色名称 = 该角色对应的权限(逗号隔开 ,可以多个)
r1=order:create,order:update
伊拉克=卖石油
  1. 创建java类 加载shiro.iniSecurityManager 获取subject ,进行认证和授权的操作
package com.aaa.shiro.demo;

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;
import org.apache.shiro.util.Factory;

import javax.security.auth.login.AccountLockedException;

/**
 * @author zhangyifan
 * @version 8.0
 * @description:
 * @date 2022/1/18 15:14
 */
public class ShiroDemo1 {
    public static void main(String[] args) {
        //1. 加载 INI 配置
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:Shiro.ini");
        //2。创建 SecurityManager
        SecurityManager securityManager = factory.getInstance();
        //3. 使其可访问
        SecurityUtils.setSecurityManager(securityManager);


        /* 认证过程*/
        //1. 获取提交的主体和凭据:
        AuthenticationToken token = new UsernamePasswordToken("admin","123456");//用户名和密码;
        //2。获取当前主题: 通常等于当前用户
        Subject subject = SecurityUtils.getSubject();//当前用户

        try {
            //3. Log in: 登录
            subject.login(token);
            //没有异常说明认证成功

            //授权过程
            //1角色判断
            if (   subject.hasRole("role2")) {
                System.out.println("拥有role2");
            }
            if (   subject.hasRole("role1")) {
                System.out.println("拥有role1");
            }
            if (   subject.hasRole("伊拉克")) {
                System.out.println("拥有伊拉克");
            }
            //2 权限判断
            if (subject.isPermitted("user:create")){
                System.out.println("当前用户拥有用户创建权限,可以进行用户创建");
            }
            if (subject.isPermitted("dept:create")){
                System.out.println("当前用户拥有部门创建权限,可以进行部门创建");
            }
            if (subject.isPermitted("dept:update")){
                System.out.println("当前用户没有部门更新权限,不可以进行部门更新");
            }
            if (subject.isPermitted("伊拉克")){
                System.out.println("可以卖石油");
            }

        } catch (AccountException e) {
            e.printStackTrace();
            System.out.println("用户名错误 !!!!");
        }catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            System.out.println("密码错误");
        }catch (AuthenticationException e){
            e.printStackTrace();
        }
        // 处理失败的登录

    }
}

示例2. 自定义加盐

  1. 创建ini文件 shiro-custom-realm.ini
[main]
#引入加密类  cm  CredentialsMatcher 认证匹配器
cm = org.apache.shiro.authc.credential.HashedCredentialsMatcher
#规定加密方式  hash哈希  AlgorithmName 算法名称
cm.hashAlgorithmName = SHA-512
#哈希次数
cm.hashIterations = 1024
# Base64 encoding (less text):如果credential 哈希是Hex 编码的话为true,base64的话为false
#cm.storedCredentialsHexEncoded = false
#配置自定义realm
myRealm=com.aaa.shiro.util.MyCustomRealm
# $cm 引用上面cm配置相当于 myRealm.setCredentialsMatcher(cm)
myRealm.credentialsMatcher = $cm
#把安全数据交给SecurityManager认证或者授权
securityManager.realms=$myRealm
  1. 编写自定义MyCustomRealm类继承AuthorizingRealm类,重写认证和授权方法
package com.aaa.shiro.util;

import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

/**
 * @author zhangyifan
 * @version 8.0
 * @description:
 * @date 2022/2/10 10:38
 */
public class MyCustomRealm extends AuthorizingRealm {
    /**
     * 授权方法
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    /**
     * 认证方法
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
               /* UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken)authenticationToken;
        //获取收集到的用户名
        String username = usernamePasswordToken.getUsername();*/
        //获取收集到的用户名
         //根据用户名或者用户对象(从数据库) 模拟realm取安全数据
        // User  user  = userService.getUserByUsername(userName);
        //获取收集的用户名
        String UserName = (String)authenticationToken.getPrincipal();//userName=admin1
        //根据用户名或者用户对象 (从数据库 模拟 reaml 取安全数据
     /*   if(user==null){
  //如果根据用户名无法查询到用户对象,说明用户名肯定错误 抛出账号错误异常
        }*/
        //获取密码
       /* String password =  user.getPassword();
        获取加密后的盐
        */
        if(!"admin".equals(UserName)){
            throw  new AccountException();
        }
        String password = "8ea0c767e2358395fc3a325893e6e86a0ae8827974584fa237bc05ff488565c82817fc6849b32c826c0798db2058af7d2897befdf00b24fe2a66781a36a5a771";
        //获取盐值  增加破解密码的复杂度
        //String saltValue =  user.getSalt();
        String saltValue ="951ef32a-8381-4f88-9f02-edd18abac632";//随机生成的你运行SHA512一次就变了
        //参数解释:1,当前根据用户名获取到的对象,后面登录成功后,可以获取使用,登录失败就作废
        //    2,加密密码(数据库取出的)
        //    3, ByteSource 对象   盐值
        //    4,  当前realm的名称

        return new SimpleAuthenticationInfo(UserName,password, ByteSource.Util.bytes(saltValue),this.getName());

    }

    /**
     * 重写可以自定义名称 不重写
     * @return
     */
    @Override
    public String getName() {
        //当前类首字母小写
        return "myCustomRealm";
    }
}

  1. 编写测试类加载 shiro_custom_realm.ini调用MyCustomRealm,完成加密加盐的认证
package com.aaa.shiro.demo;

import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
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.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;

/**
 * @author zhangyifan
 * @version 8.0
 * @description:
 * @date 2022/2/10 10:45
 */
public class ShiroDemoB {
    public static void main(String[] args) {
        //加载配置
        Factory<SecurityManager> factory =
                new IniSecurityManagerFactory("classpath:shiro-custom-realm.ini");
        //获取SecurityManager
        SecurityManager securityManager = factory.getInstance()                     ;
        //激活SecurityManager
        SecurityUtils.setSecurityManager(securityManager);

        //收集SecurityManager
        AuthenticationToken usernamePasswordToken =
                new UsernamePasswordToken("admin","123456");


            //获取当前主题
        Subject curretUser = SecurityUtils.getSubject();

        //
        try {//进行登录认证
            curretUser.login(usernamePasswordToken);
            System.out.println("登录成功");
            Session session = curretUser.getSession();
             /* User user = (User)currentUser.getPrincipal();//通过SimpleAuthenticationInfo对象的第一参数获取的
            session.setAttribute("userInfo",user);*/
        } catch (AccountException e) {
            e.printStackTrace();
            System.out.println("用户名错误 !!!!");
        }catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            System.out.println("密码错误");
        }catch (AuthenticationException e){
            e.printStackTrace();
            System.out.println("用户名或者密码错误!!!");
        }
        //退出
        curretUser.logout();

    }
}

  1. 模拟注册时生成密码的工具类:
package com.aaa.shiro.util;

import org.apache.shiro.crypto.hash.Sha512Hash;
import java.util.UUID;
/**
 * @author zhangyifan
 * @version 8.0
 * @description:
 * @date 2022/2/10 11:23
 */
public class SHA512Test {
    public static void main(String[] args) {
        String orginalPassword="123456";
         //随机颜值
        String saltValue = UUID.randomUUID().toString();
        System.out.println("盐值" +saltValue);

        //shrio 加密的应用
        // 参数 1. 原始密码 2. 随机盐值 3. 哈希次数 (和配置对应)
        Sha512Hash sha512Hash=
                new Sha512Hash(orginalPassword,saltValue,1024);

        //加密后的密码
        String spassword = sha512Hash.toString();

        //打印密码
        System.out.println(spassword);
    }
}

示例jdbcrealm

  1. jar包
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-core</artifactId>
      <version>1.8.0</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.0.4</version>
    </dependency>

    <dependency>
      <groupId>commons-dbcp</groupId>
      <artifactId>commons-dbcp</artifactId>
      <version>1.4</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.21</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.48</version>
    </dependency>

  1. 创建ini文件
#数据源
dataSource=com.alibaba.druid.pool.DruidDataSource
#数据源连接要素  dataSource.driverClassName=com.mysql.cj.jdbc.Driver
dataSource.driverClassName=com.mysql.jdbc.Driver
#mysql 3306 sqlserver 1433
dataSource.url=jdbc:mysql://localhost:3306/tab_account?serverTimezone=GMT%2B8&yesSSL=false
dataSource.username=root
dataSource.password=04161220
#jdbcrealm
jdbcrealm=org.apache.shiro.realm.jdbc.JdbcRealm
#jdbcrelam需要的数据源
jdbcrealm.dataSource=$dataSource
#开启查找权限
jdbcrealm.permissionsLookupEnabled=true
#设置安全管理器使用的jdbcrealm
securityManager.realms=$jdbcrealm

  1. 测试类
package org.example.shrio;

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;
import org.apache.shiro.util.Factory;

/**
 * @author zhangyifan
 * @version 8.0
 * @description: jdbcrealm
 * @date 2022/2/10 15:09
 */
public class ShrioTestC     {
    public static void main(String[] args) {
        //加载配置
        Factory<SecurityManager> factory =
                new IniSecurityManagerFactory("classpath:shiro_jdbcrealm_mysql.ini");
    //工厂获取SecurityMannger
        SecurityManager securityManager = factory.getInstance();
        //访问
        SecurityUtils.setSecurityManager(securityManager);
        //获取Subject
        Subject currentUser = SecurityUtils.getSubject();

        //判断是否认证
        if (!currentUser.isAuthenticated()){
            //收集客户端 提交的用户和密码
            AuthenticationToken token = new UsernamePasswordToken("scott", "tiger1");
            //提交收集的数据给SecurityMananger 做认证处理this.securityManager.
            //org.apache.shiro.authc.Authenticator  authenticate方法,认证
            try {


                currentUser.login(token);
                System.out.println("认证成功");
                //授权
                //角色
                System.out.println("scott用户是否具有role1角色:"+currentUser.hasRole("role1"));//true
                System.out.println("scott用户是否具有role3角色 "+currentUser.hasRole("role3"));//false
                //权限
                System.out.println("scott用户是否具有dept:select 权限 "+ currentUser.isPermitted("dept:select"));//true
                System.out.println("scott用户是否具有dept:select权限:"+currentUser.isPermitted("dept:alter"));//false
            } catch (AccountException e){
                System.out.println("用户名错误");
            }catch (IncorrectCredentialsException e){
                System.out.println("密码错误");
            }catch (AuthenticationException e) {
                e.printStackTrace();
            }
            //当前用户退出
            currentUser.logout();
        }

    }
}

  1. 数据库
create table users(  username  varchar(20),  password varchar(50),  age int(3));

-- 添加数据
INSERT INTO users
VALUES
	( 'scott', 'tiger', 10 );
INSERT INTO users
VALUES
	( 'admin', 'tiger', 20 );
INSERT INTO users
VALUES
	( 'smith', 'tiger', 30 );
	
	-- 用户角色关联表 user_roles
create TABLE user_roles (
role_name VARCHAR ( 20 ),
username VARCHAR ( 20 ));




-- 添加数据

 INSERT INTO user_roles
VALUES
	( 'role1', 'scott' );
INSERT INTO user_roles
VALUES
	( 'role2', 'scott' );
INSERT INTO user_roles
VALUES
	( 'role2', 'admin' );
INSERT INTO user_roles
VALUES
	( 'role3', 'smith' );
	
	-- 角色权限关联表 roles_permissions
	create TABLE roles_permissions (
role_name VARCHAR ( 20 ),
permission VARCHAR ( 100 ));

-- 添加数据
INSERT INTO roles_permissions
VALUES
	( 'role1', 'dept:select' );
INSERT INTO roles_permissions
VALUES
	( 'role1', 'dept:update' );
INSERT INTO roles_permissions
VALUES
	( 'role1', 'dept:delete' );
INSERT INTO roles_permissions
VALUES
	( 'role2', 'user:select' );
INSERT INTO roles_permissions
VALUES
	( 'role2', 'user:update' );
INSERT INTO roles_permissions
VALUES
	( 'role3', 'user:delete' );
	
	
	
	-- 检查
	
SELECT	* FROM	users;
SELECT	* FROM	user_roles;
SELECT	* FROM	roles_permissions;
posted @ 2022-02-10 16:31  啧啧啧|(* ̄ ̄*)  阅读(13)  评论(0)    收藏  举报  来源