Shiro安全框架【认证】+【授权】
1、Shiro的核心架构

- Subject:程序主体
- Security Manager:安全管理器
- Authentication:做认证
- Authorizer:做授权
- Session Manager:会话管理器(管理整个Web会话核心)
- Session Manager:GRUD管理(增删改查)
- Cache Manager:缓存管理器(减小资源压力)
- Pluggable Realms:获取认证和授权的相应数据并完成相应的认证和授权操作
- Cryptography:算法生成器,密码生成器
2、Shiro中的认证
- Subject:主体
- 访问系统的用户,主体可以是用户、程序等
- Principal:身份信息
- 主体(subject)进行身份认证的标识,标识具有唯一性,可以有多个身份,但是必须得有一个主身份(Primary Principal)
- Credential:凭证信息
- 只有主体自己知道的安全信息
认证流程
编码实现:
public class TestAuthentication {
//实现认证
public static void main(String[] args) {
//0、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
//1、创建安全管理器
SecurityManager securityManager = factory.getInstance();
//2、SecurityUtils 给全局安全工具类设置安全管理器
SecurityUtils.setSecurityManager(securityManager);
//4、关键对象subject主体
Subject subject = SecurityUtils.getSubject();
//5、创建令牌(Token)
UsernamePasswordToken token = new UsernamePasswordToken("xiaocheng", "123");
try {
//认证状态
System.out.println("认证状态:" + subject.isAuthenticated());
subject.login(token);//用户认证
//认证状态
System.out.println("认证状态:" + subject.isAuthenticated());
} catch (UnknownAccountException e) {
System.out.println("认证失败:{用户不存在}");
} catch (IncorrectCredentialsException e) {
System.out.println("认证失败:{密码不存在}");
}
}
}
- 最终执行用户名比较的类SimpleAccountRealm
- 在该类中的doGetAuthenticationInfo方法中完成了用户名的校验
后续的方法中,我们会在这个方法中来进行完成数据库的认证
- 在该类中的doGetAuthenticationInfo方法中完成了用户名的校验
- 最终执行密码校验的类AuthenticatingRealm
- 在该类中的assertCredentialsMatch方法中完成了密码的校验
密码则是在自动返回信息后自动进行校验的
- 在该类中的assertCredentialsMatch方法中完成了密码的校验
总结:
AuthenticatingRealm 认证realm doGetAuthenticationInfo
AuthorizeingRealm 授权realm doGetAuthorizationInfo
如果要自定义Realm的话自己写一个Realm然后继承AuthorizeingRealm然后可以重写两个类中的doGetAuthenticationInfo和doGetAuthorizationInfo方法
3、自定义认证
/**
* 使用自定义realm来进行认证
*/
public class TestCustomerRealmAuthenticator {
public static void main(String[] args) {
//创建安全管理器securityManager
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
//设置自定义realm
defaultSecurityManager.setRealm(new CustomerRealm());
//将安全工具类设置安全管理器
SecurityUtils.setSecurityManager(defaultSecurityManager);
//获取通过安全工具了获取subject
Subject subject = SecurityUtils.getSubject();
//创建token
UsernamePasswordToken token = new UsernamePasswordToken("xiaocheng", "123");
try{
subject.login(token);
System.out.println("认证成功!");
}catch (IncorrectCredentialsException e){
System.out.println("密码错误");
}catch (UnknownAccountException e){
System.out.println("用户名错误");
}
}
}
/**
* 自定义认证Realm
* 将认证/授权的数据的来源转为模拟数据库的实现
*/
public class CustomerRealm extends AuthorizingRealm {
//授权方法
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
//认证方法
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//在token中获取用户名
Object principal = authenticationToken.getPrincipal();
System.out.println(principal);
//根据身份信息去使用jdbc获取相关的数据库
if ("xiaocheng".equals(principal)) {
//参数1代表返回数据库中正确的用户名
//参数2代表返回数据库中正确的密码
//参数3提供当前Realm的名字 this.getName()
//模拟数据库的实现
return new SimpleAuthenticationInfo(principal,"123", this.getName());
}
return null;
}
}
4、使用MD5和Salt(盐)加密明文数据
可以理解为给MD5加盐,齁得慌。所以加密的后的数据就更复杂了
md5(明文密码+盐) => {复杂密文} => md5(复杂密文+盐) => {复杂密文plush}
MD5算法一般用来做加密和签名,特点是不可逆的。只能根据明文来生成密文而不能通过密文来反推明文。如果内容相同无论执行多少次MD5生产的结果始终是一致的
MD5生成结果特点:
始终是一个16进制32位长度的字符串
使用方式
public class TestShiroMD5 {
public static void main(String[] args) {
//使用MD5
Md5Hash md5Hash = new Md5Hash("123");
System.out.println(md5Hash.toHex());
//使用MD5+salt加盐处理
Md5Hash md5Hash1 = new Md5Hash("123", "X0*7ps");
System.out.println(md5Hash1.toHex());
//使用MD5 + salt + hash散列
Md5Hash md5Hash2 = new Md5Hash("123", "X0*7ps", 1024);
System.out.println(md5Hash2.toHex());
}
}
改造Shiro认证流程已经加密的处理
public class TestCustromerMd5RealmAuthenication {
public static void main(String[] args) {
//创建安全管理器
DefaultSecurityManager securityManager = new DefaultSecurityManager();
//注入自定义的realm
CustomerMd5Realm realm = new CustomerMd5Realm();
//设置realm使用hash凭证匹配器
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
credentialsMatcher.setHashAlgorithmName("md5");
//hash散列1024次
credentialsMatcher.setHashIterations(1024);
realm.setCredentialsMatcher(credentialsMatcher);
securityManager.setRealm(realm);
//将安全管理器注入安全工具类
SecurityUtils.setSecurityManager(securityManager);
//通过安全工具类获取Subject
Subject subject = SecurityUtils.getSubject();
//认证
UsernamePasswordToken token =
new UsernamePasswordToken("xiaocheng", "123");
try {
subject.login(token);
System.out.println("验证成功");
} catch (UnknownAccountException e) {
System.out.println("用户名错误");
} catch (IncorrectCredentialsException e) {
System.out.println("密码错误");
}
}
}
/**
* 使用自定义realm去加入md5+salt+hash
*/
public class CustomerMd5Realm extends AuthorizingRealm {
//授权方法
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
//认证方法
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//获取身份信息
String principal = (String) authenticationToken.getPrincipal();
//根据用户名查询数据库
if ("xiaocheng".equals(principal)) {
//参数1:用户名
//参数2:md5+salt之后的密码
//参数3:注册时的随机盐
//参数4:realm的名字
return new SimpleAuthenticationInfo(principal,
"e4f9bf3e0c58f045e62c23c533fcf633",
ByteSource.Util.bytes("X0*7ps"),
this.getName());
}
return null;
}
}
5、Shiro中的授权
授权就是访问控制,控制谁能访问和修改哪些资源
对认证之后的用户来进行权限的赋予
授权方式
基于角色的访问控制
RBAC(Role-Based Access Control)基于角色的访问控制
if(subject.hasRole("admin")){ //资源实例
//操作资源
}
基于资源的访问控制
RBAC(Resource-Based Access Control)是以资源为中心进行控制访问
if(subject.IsPermissions("user:find:*")){ //资源类型
//对所有用户具有查询权限
}
权限字符串
规则
资源标识符:操作:资源实例标识符
意思是对哪个资源的哪个实例具有什么操作,":"是 资源/操作/实例的分隔符,权限字符串也可以使用*通配符。
- 用户创建权限: user:create,或user:create:*
- 用户修改实例001的权限: user:update:001
- 用户实例001的所有权: user:*:001
通过编码实现授权
public class CustomerMd5Realm extends AuthorizingRealm {
//授权方法
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("========开始授权========");
//获取身份信息,使用身份信息在数据库中查看具有哪些身份信息和权限
String principal = (String) principalCollection.getPrimaryPrincipal();
System.out.println("主身份 " + principal);
//将数据库中查询的角色信息赋值给权限对象(模拟)
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.addRole("admin");
simpleAuthorizationInfo.addRole("user");
//将数据库中的权限信息赋值给权限对象
//当前用户只对01用户有操作权限
simpleAuthorizationInfo.addStringPermission("user:*:01");
//对商品具有创建权限
simpleAuthorizationInfo.addStringPermission("produce:create");
return simpleAuthorizationInfo;
}
//认证方法
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//获取身份信息
String principal = (String) authenticationToken.getPrincipal();
//根据用户名查询数据库
if ("xiaocheng".equals(principal)) {
//参数1:用户名
//参数2:md5+salt之后的密码
//参数3:注册时的随机盐
//参数4:realm的名字
return new SimpleAuthenticationInfo(principal,
"e4f9bf3e0c58f045e62c23c533fcf633",
ByteSource.Util.bytes("X0*7ps"),
this.getName());
}
return null;
}
}
public class TestCustromerMd5RealmAuthenication {
public static void main(String[] args) {
//创建安全管理器
DefaultSecurityManager securityManager = new DefaultSecurityManager();
//注入自定义的realm
CustomerMd5Realm realm = new CustomerMd5Realm();
//设置realm使用hash凭证匹配器
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
credentialsMatcher.setHashAlgorithmName("md5");
//hash散列1024次
credentialsMatcher.setHashIterations(1024);
realm.setCredentialsMatcher(credentialsMatcher);
securityManager.setRealm(realm);
//将安全管理器注入安全工具类
SecurityUtils.setSecurityManager(securityManager);
//通过安全工具类获取Subject
Subject subject = SecurityUtils.getSubject();
//认证
UsernamePasswordToken token =
new UsernamePasswordToken("xiaocheng", "123");
try {
subject.login(token);
System.out.println("验证成功");
} catch (UnknownAccountException e) {
System.out.println("用户名错误");
} catch (IncorrectCredentialsException e) {
System.out.println("密码错误");
}
//认证的用户进行授权
if (subject.isAuthenticated()) {
//1.基于角色的权限控制,查看是否有admin权限
System.out.println("是否具有多角色admin : " + subject.hasRole("admin"));
//2.基于多角色的权限控制
System.out.println("是否具有多角色: " + subject.hasAllRoles(Arrays.asList("admin", "user")));
//3.是否具有其中一个角色
boolean[] booleans = subject.hasRoles(Arrays.asList("admin", "super", "user"));
for (boolean aBoolean : booleans) {
System.out.println(aBoolean);
}
System.out.println("+++++++++++++++++++++++=");
//4.基于权限字符串的访问控制 资源标识符:操作:资源类型/实例
//是否具有整个user的操作权限
System.out.println("权限:" + subject.isPermitted("user:*:01"));
//判断对01用户有没有修改操作
System.out.println("用户修改权限:" + subject.isPermitted("user:update:01"));
//判断对所有商品是否具有修改权限
System.out.println("商品修改权限:" + subject.isPermitted("produce:update"));
//判断对所有商品是否具有创建权限
System.out.println("商品修改权限:" + subject.isPermitted("produce:create"));
//判断对所有商品是否具有创建01号创建权限
System.out.println("商品修改权限:" + subject.isPermitted("produce:create:02"));
//分别具有哪些权限
boolean[] booleans1 = subject.isPermitted("user:*:01", "order:*:10");
for (boolean b : booleans1) {
System.out.println("分别具有哪些权限: " + b);
}
//同时具有哪些权限
boolean all = subject.isPermittedAll("user:*:01", "produce:create:01");
System.out.println("同时具有权限: " + all);
}
}
}
Shiro安全框架【认证】+【授权】的更多相关文章
- SpringBoot整合Shiro 四:认证+授权
搭建环境见: SpringBoot整合Shiro 一:搭建环境 shiro配置类见: SpringBoot整合Shiro 二:Shiro配置类 shiro整合Mybatis见:SpringBoot整合 ...
- 5、Shiro之jdbcRealm认证授权
登录认证: 注意,下面我是以连接orcal数据库为例的依赖,如果各位同仁使用的是骑她数据库,可以换成对应数据库的依赖(数据源不用换) Pom.xml增加依赖: <!--引入连接orcal的jar ...
- 用户登录安全框架shiro—用户的认证和授权(一)
ssm整合shiro框架,对用户的登录操作进行认证和授权,目的很纯粹就是为了增加系统的安全线,至少不要输在门槛上嘛. 这几天在公司独立开发一个供公司内部人员使用的小管理系统,客户不多但是登录一直都是 ...
- shiro框架学习-2-springboot整合shiro及Shiro认证授权流程
1. 添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...
- Java环境下shiro的测试-认证与授权
Java环境下shiro的测试 1.导入依赖的核心jar包 <dependency> <groupId>org.apache.shiro</groupId> < ...
- SpringBoot整合shiro实现用户的认证授权
* 项目环境搭建 * 配置ShiroConfig,用于shiro的基本配置和注入自定义规则 * 实现自定义的realm,继承AuthorizingRealm * 编写测试controller和页面 基 ...
- Shiro的认证授权
shiro安全框架入门整理 package com.shiro.test; import org.apache.shiro.SecurityUtils; import org.apache.shiro ...
- Shiro身份认证授权原理
shiro在应用程序中的使用是用Subject为入口的, 最终subject委托给真正的管理者ShiroSecurityMannager Realm是Shiro获得身份认证信息和来源信息的地方(所以这 ...
- Apache Shiro权限框架在SpringMVC+Hibernate中的应用
在做网站开发中,用户权限必须要考虑的,权限这个东西很重要,它规定了用户在使用中能进行哪 些操作,和不能进行哪些操作:我们完全可以使用过滤器来进行权限的操作,但是有了权限框架之后,使用起来会非常的方便, ...
- shiro安全框架
原文:http://blog.csdn.net/boonya/article/details/8233303 可能大家早先会见过 J-security,这个是 Shiro 的前身.在 2009 年 3 ...
随机推荐
- excel江湖异闻录--华麒麟
认识他应该是在18.19年左右,那时就感觉这也是个高手,同大部分的高手一样,痴迷函数,热衷创造.挑战不规范的数据. 后来他消失了好长一段时间,群里的同学都以为他退圈了,偶有少数的同学想起他,言语都带着 ...
- 某小说解锁VIP
在User类中定位到这个方法,尝试直接返回true 可以发现apk显示了vip的到期时间,测试一下vip是否有效 显然这个vip是没起作用的,还有地方在控制这个vip的方法.在jadx中查看交叉引用 ...
- C++ 第一节课 名字空间 ,输入输出函数,和 C 语言的区别
#include <iostream> // #include 头文件,C++标准库的头文件都不带 .h (.h 是C库头文件添加的) #include <cstdio> #i ...
- 这十年我与广告不共戴天练就的十八般武艺 #PC去广告 #手机去广告
背景 大家应该都体会过广告的苦恼,比如看着好看的电视,突然给播放广告,这时候痛苦系数飙升.随着社会进步,广告的载体,还有形式也越来越多,比如手机端各种APP启动广告,PC端软件弹窗,网站Banner等 ...
- windows涉及所有协议及默认端口
名称 协议 端口 说明 echo tcp/udp 7 echo服务 discard tcp/udp 9 用于连接测试的空服务 systat tcp/udp 11 链接端口系统状态 daytime tc ...
- 多元/多维高斯/正态分布概率密度函数推导 (Derivation of the Multivariate/Multidimensional Normal/Gaussian Density)
各种维度正态分布公式: 一维正态分布 二维正态分布/多维正态分布 各向同性正态分布 注:即方差都是一样的,均值不一样,方差的值可以单独用标量表示. 多元/多维高斯/正态分布概率密度函数推导 (Deri ...
- IntelliJ IDEA 2024激活码(亲测有效,仅供学习和交流)
资源是从官网购买,仅供学习和交流 激活码链接地址
- 3.2 Linux文件系统到底有什么用处?
Linux 上常见的文件系统是EXT3或EXT4,但这篇文章并不准备一上来就直接讲它们,而希望结合Linux操作系统并从文件系统建立的基础--硬盘开始,一步步认识Linux的文件系统. 1.机械硬盘的 ...
- 开源 PHP 商城项目 CRMEB 二次开发和部署教程
上篇文章给大家介绍了如何使用 Sealos 应用商店一键部署 CRMEB 开源商城系统,那速度真叫一个快啊,比宝塔快多了! 但是有些读者还不满足于此,问我能不能边运行边改代码,而且还得用 Cursor ...
- Java真的没出路了吗?
Java从1991年由James Gosling和他的同事们开发, 至今已经三十多年, 我们知道,任何产品都有生命周期, 都要经历从诞生.发展.成熟.消亡四个阶段, 目前的Java已经处在成熟阶段, ...