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
身份验证是验证用户身份的过程。也就是说,当用户通过应用程序进行身份验证时,他们在证明自己实际上就是他们所说的身份。有时也称为“登录”。这通常是一个三步过程。
- 收集用户的标识信息(称为主体 用户名)和支持身份的凭证(称为凭据 密码)。
AuthenticationToken token = new UsernamePasswordToken(username, password);
- 将主体和凭据提交到系统。
Subject currentUser = SecurityUtils.getSubject();
currentUser.login(token);
- 如果提交的凭据与系统对该用户身份的期望匹配,则认为该用户已通过身份验证。如果它们不匹配,则不认为用户已通过身份验证。
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.
- 创建基础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>
- 创建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
伊拉克=卖石油
- 创建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. 自定义加盐
- 创建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
- 编写自定义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";
}
}
- 编写测试类加载 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();
}
}
- 模拟注册时生成密码的工具类:
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
- 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>
- 创建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
- 测试类
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();
}
}
}
- 数据库
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;


浙公网安备 33010602011771号