Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用
1 Realm简介
1.1 Realm作用
shiro最终是通过Realm获取安全数据的(如用户、角色、权限),也就是说认证或者授权都会通过Realm进行数据操作
1.2 Realm接口
1.2.1 源代码
1.2.2 方法说明
》getName:返回一个唯一的 Realm 名字
》supports:判断此 Realm 是否支持此 Token
》getAuthenticationInfo:根据 Token 获取认证信息,该方法就是用来实现认证逻辑的(从Realm的实现类org.apache.shiro.realm.AuthenticatingRealm#getAuthenticationInfo中可以看出)
1.3 AuthenticationToken
》层级关系
》关系图
》开发时一般将用户名和密码封装成一个UsernamePasswordToken对象
1.4 注意
》supports需要对Token类型进行判断,判断实参类型是否满足条件;这里指定的是AuthenticationToken类型(任何Token类型都可以传入,因为AuthenticationToken是一个父接口),所以在实现类中只需要判断实参是否是指定的Token类型即可(实际开发时传入的实参一般都是UsernamePasswordToken类型,所以在supports方法中只需要判定实参是否是这个类型即可)。
》实现认证的逻辑就是写在org.apache.shiro.realm.Realm#getAuthenticationInfo这个方法中的(从Realm的实现类org.apache.shiro.realm.AuthenticatingRealm#getAuthenticationInfo中可以看出)
1.5 简易自定义Realm
1.5.1 思路
》实现Realm接口
》getName返回一个唯一的Realm名称即可
》supports中判定实参类型是否是UsernamePasswordToken类型
》getAuthenticationInfo中实现认证逻辑
1.5.2 代码实现
package com.xunyji.demo03.shirotest.realm; import org.apache.shiro.authc.*;
import org.apache.shiro.realm.Realm; /**
* @author AltEnter
* @create 2019-01-20 20:11
* @desc 自定义简易Realm
**/
public class MySimpleRealm implements Realm { public String getName() {
return "mySimpleRealm";
} public boolean supports(AuthenticationToken token) {
if (token instanceof UsernamePasswordToken) {
return true;
}
return false;
} public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String) token.getPrincipal();
String password = new String((char[])token.getCredentials());
System.out.println(String.format("用户名为:%s, 用户密码为:%s", username, password));
if (!"fury".equals(username)) {
System.out.println("用户名错误");
return null;
}
if (!"111111".equals(password)) {
System.out.println("密码错误");
return null;
} return new SimpleAuthenticationInfo(username, password, getName());
}
}
1.5.3 单元测试类
package com.xunyji.demo03.shirotest.realm; import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Test; import static org.junit.Assert.*; public class MySimpleRealmTest { @Test
public void test01() {
MySimpleRealm mySimpleRealm = new MySimpleRealm();
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
defaultSecurityManager.setRealm(mySimpleRealm);
SecurityUtils.setSecurityManager(defaultSecurityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("fury", "111111");
subject.login(token);
System.out.println(String.format("认证结果:%s", subject.isAuthenticated())); } }
2 Realm源码分析
Realm接口主要是认证的主接口,但是它的一些实现类既可以进行认证也可以进行授权逻辑
2.1 Realm相关类层次图
todo: 贴图
2.2 Realm相关类说明
》CachingRealm:带有缓存实现的Realm,相当于Realm的扩展
》AuthenticatingRealm:专门做认证的Realm,它继承自CachingRealm
》AuthorizingRealm:专门做授权的Realm,因为它集成自AuthenticatingRealm,所以它也可以实现认证逻辑;自定义的Realm一般都是继承该类,然后重写里面的认证方法和授权方法即可。
》IniRealm:用ini文件存储用户信息时使用,[users]部分指定用户名/密码及其角色; [roles]部分指 定角色即权限信息;
》PropertiesRealm:用properties文件存储用户信息时使用,user.username=password,role1,role2 指定用户 名/密码及其角色;role.role1=permission1,permission2 指定角色及权限信息;
》JdbcRealm:用数据库存储用户信息时使用,通过 sql 查询相应的信息,如“select password from users where username = ?”获取用户密码,“select password, password_salt from users where username = ?”获取用户密码及盐;“select role_name from user_roles where username = ?” 获取用户角色;“select permission from roles_permissions where role_name = ?”获取角色对 应的权限信息;也可以调用相应的 api 进行自定义 sql;
2.3 AuthenticatingRealm详解
》getAuthenticationInfo:该方法是Realm中getAuthenticationInfo的实现,该方法是实现认证逻辑的;该方法是一个final方法,所以AuthenticatingRealm的子类不能重写该方法;
》doGetAuthenticationInfo:getAuthenticationInfo方法调用doGetAuthenticationInfo实现认证逻辑,该方法是一个protected方法,专门暴露给子类进行重写的,而且是子类实现认证逻辑必须重写的方法。
2.4 Realm主要实现类
2.4.1 IniRealm
》用户相关信息存储在一个ini文件中
2.4.2 PropertiesRealm
》用户相关信息存储在一个properties文件中
2.4.3 JdbcRealm
》用户信息存储在数据库中
2.5 IniRealm使用教程
2.5.1 继承关系图

2.5.2 创建一个maven工程并引入shiro、junit相关依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency> <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
2.5.3 在resources目录下创建ini文件用于存放用户信息
》项目目录结构

https://blog.csdn.net/u011781521/article/details/74892074
》ini文件内容
[users]
fury=111111,role1,role2
zeus=222222,role1
[roles]
role1=user:delete,user:update,user:create,user:read
role2=car:create
》测试代码
package com.xunyji.demo03.shirotest.realm; import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Test; import java.util.ArrayList;
import java.util.Arrays; /**
* @author AltEnter
* @create 2019-01-17 22:07
* @desc IniRealm测试类
**/
public class IniRealmDemo { @Test
public void iniRealmTest() {
// 01 创建Realm
IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
// 02 创建SecurityManager并将Realm设置到SecurityManager中
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
defaultSecurityManager.setRealm(iniRealm); // 03 将SecurityManager设置到SecurityUtils中
SecurityUtils.setSecurityManager(defaultSecurityManager);
// 04 从SecurityUtils中获取Subject
Subject subject = SecurityUtils.getSubject();
// 05 将用户名和用户密码封装成一个Token
UsernamePasswordToken token = new UsernamePasswordToken("zeus", "222222");
// 06 通过Subject进行登录认证
try {
subject.login(token);
} catch (Exception e) {
e.printStackTrace();
}
// 07 通过Subject判断登录认证结果
System.out.println(String.format("认证结果为:%s", subject.isAuthenticated())); ArrayList<String> roleList = new ArrayList<String>();
roleList.add("role1");
System.out.println("是否有role1角色:" + Arrays.toString(subject.hasRoles(roleList)));
System.out.println("是否有role1角色:" + subject.hasRole("role1"));
subject.checkPermission("user:create");
} }
2.6 PropertiesRealm使用教程
参见2.5 + 百度
2.7 JdbcRealm使用教程
》继承关系图

》引入shiro、junit、mysql、druid依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency> <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency> <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.45</version>
</dependency> <dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.6</version>
</dependency>
》根据JdbcRealm源码创建相关表的SQL
/*
Navicat MySQL Data Transfer Source Server : mysql5.4
Source Server Version : 50540
Source Host : localhost:3306
Source Database : shiro Target Server Type : MYSQL
Target Server Version : 50540
File Encoding : 65001 Date: 2019-01-17 21:07:56
*/ SET FOREIGN_KEY_CHECKS=0; -- ----------------------------
-- Table structure for `roles_permissions`
-- ----------------------------
DROP TABLE IF EXISTS `roles_permissions`;
CREATE TABLE `roles_permissions` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`role_name` varchar(255) NOT NULL,
`permission` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4; -- ----------------------------
-- Records of roles_permissions
-- ----------------------------
INSERT INTO `roles_permissions` VALUES ('', 'admin', 'user:update'); -- ----------------------------
-- Table structure for `user_roles`
-- ----------------------------
DROP TABLE IF EXISTS `user_roles`;
CREATE TABLE `user_roles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) NOT NULL,
`role_name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4; -- ----------------------------
-- Records of user_roles
-- ----------------------------
INSERT INTO `user_roles` VALUES ('', 'fury', 'admin');
INSERT INTO `user_roles` VALUES ('', 'fury', 'user'); -- ----------------------------
-- Table structure for `users`
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4; -- ----------------------------
-- Records of users
-- ----------------------------
INSERT INTO `users` VALUES ('', 'fury', '');
》测试类
package com.xunyji.demo03.shirotest.realm; import com.alibaba.druid.pool.DruidDataSource;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Test; /**
* @author AltEnter
* @create 2019-01-20 21:07
* @desc JdbcRealm使用Demo
**/
public class JdbcRealmDemo {
DruidDataSource data =new DruidDataSource();
{
data.setUrl("jdbc:mysql://localhost:3306/shiro?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC");
data.setUsername("root");
data.setPassword("182838");
}
@Test
public void testAuthentication(){ JdbcRealm jdbcRealm = new JdbcRealm();
jdbcRealm.setDataSource(data);
jdbcRealm.setPermissionsLookupEnabled(true); // 开启权限查询功能
String sql="select password from users where username= ?";
jdbcRealm.setAuthenticationQuery(sql); String roleSql ="select role_name from user_roles where username = ?";
jdbcRealm.setUserRolesQuery(roleSql); //1.构建securtymanager
DefaultSecurityManager manager = new DefaultSecurityManager();
manager.setRealm(jdbcRealm); //2.主体提交认证请求
SecurityUtils.setSecurityManager(manager);
Subject subject = SecurityUtils.getSubject(); // UsernamePasswordToken token =new UsernamePasswordToken("Mark","123456");
UsernamePasswordToken token =new UsernamePasswordToken("fury","111111");
subject.login(token); //是否认证的一个方法
boolean authenticated = subject.isAuthenticated();
System.out.println("authenticated==============="+authenticated);
subject.checkRole("user");
subject.checkRole("admin"); subject.checkPermission("user:update"); }
}
2.8 SimpleAccountRealm使用教程
》层次关系图

》说明
这种类型是通过硬编码来存储用户数据的
》测试代码
package com.xunyji.demo03.shirotest.realm; import com.sun.org.apache.bcel.internal.generic.NEW;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Before;
import org.junit.Test; /**
* @author AltEnter
* @create 2019-01-20 21:15
* @desc SimpleAccountRealm使用Demo类
**/
public class SimpleAccountRealmDemo { private SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm(); @Before
public void addUser() {
simpleAccountRealm.addAccount("fury", "111111");
} @Test
public void test01() {
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
defaultSecurityManager.setRealm(simpleAccountRealm); SecurityUtils.setSecurityManager(defaultSecurityManager);
Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("fury", "111111"); subject.login(token); System.out.println(String.format("认证结果为:%s", subject.isAuthenticated())); subject.logout(); System.out.println(String.format("认证结果为:%s", subject.isAuthenticated())); }
}

Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用的更多相关文章
- 自定义shiro的Realm实现和CredentialsMatcher实现以及Token实现
Realm是shiro比较核心的接口,简单说它的实现类就是校验用户输入的账号信息的地方.如果想自定义实现一般的配置文件如下: <!--自定义Realm 继承自AuthorizingRealm - ...
- 自定义MVC框架之工具类-模型类
截止目前已经改造了5个类: ubuntu:通过封装验证码类库一步步安装php的gd扩展 自定义MVC框架之工具类-分页类的封装 自定义MVC框架之工具类-文件上传类 自定义MVC框架之工具类-图像处理 ...
- 自定义MVC框架之工具类-图像处理类
截止目前已经改造了4个类: ubuntu:通过封装验证码类库一步步安装php的gd扩展 自定义MVC框架之工具类-分页类的封装 自定义MVC框架之工具类-文件上传类 图像处理类: 1,图片加水印处理( ...
- 自定义MVC框架之工具类-文件上传类
截止目前已经改造了3个类: ubuntu:通过封装验证码类库一步步安装php的gd扩展 自定义MVC框架之工具类-分页类的封装 该文件上传类功能如下: 1,允许定制上传的文件类型,文件mime信息,文 ...
- JVM 自定义类加载器在复杂类情况下的运行分析
一.自定义类加载器在复杂类情况下的运行分析 1.使用之前创建的类加载器 public class MyTest16 extends ClassLoader{ private String classN ...
- Android开发之制作圆形头像自定义View,直接引用工具类,加快开发速度。带有源代码学习
作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985 QQ986945193 博客园主页:http://www.cnblogs.com/mcxiaobing ...
- IDEA自定义liveTemplates(方法模板、类模板)
IDEA自定义liveTemplates(方法模板.类模板) 前言,搞这个模板有何意义? 降低大家写方法注释的成本,统一风格.有时候不是开发同学不爱写注释,而是没有合适的载体和空间. IDEA模板设置 ...
- Shiro第二篇【介绍Shiro、认证流程、自定义realm、自定义realm支持md5】
什么是Shiro shiro是apache的一个开源框架,是一个权限管理的框架,实现 用户认证.用户授权. spring中有spring security (原名Acegi),是一个权限框架,它和sp ...
- Shiro - 自定义filterChainDefinitions和Realm
在Spring Context中定义shiroFilter(org.apache.shiro.spring.web.ShiroFilterFactoryBean)时需要为其filterChainDef ...
随机推荐
- PostgreSQL psql中如何查看快捷功能的对应函数
在psql中,我们可以通过一系列的的快捷命令查看数据库元素,如:\d 查看当前搜索路径下的表,那么内部用到的SQL语句是什么呢,可以通过命令来设置是否打印出来: apple=# \set ECHO_H ...
- 使用c++实现一个FTP客户端(三)
接上篇:http://www.cnblogs.com/jzincnblogs/p/5217688.html,这篇主要记录编程过程中需要注意的地方以及遇到的一些问题及解决方法. 一.gethostbyn ...
- 第30课 C语言中的字符串
任意的软件开发过程都会涉及到字符串,字符串的概念: ca是字符数组,其他几个都是字符串,因为最后都有'\0'. 示例程序如下: #include <stdio.h> int main() ...
- VMware 虚拟机快照、克隆、磁盘扩容
1. 快照 快照是虚拟机某个时间点上完整系统的镜像,可以在虚拟机内部通过快照文件恢复系统到之前的节点. 拍摄快照: 恢复快照: 2. 克隆 克隆是原始虚拟机全部状态的一个拷贝,是脱离原始虚拟机独立存在 ...
- 树的直径证明+HDU2196
首先把无向图变成一棵树,直径肯定由叶子组成. 有以下两种情况: 第一种:经过根节点,则找两个最远的叶子肯定是直径,也就是B+D. 第二种:不经过根节点,则目标的两个叶子肯定有一个不为根的公共祖先,如红 ...
- ECUST 12级 Practise
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=26399#overview 果断开小号水过 CodeForces 58A #include ...
- Keep On Movin
上回书说道不愿透露姓名的巨巨还剩下一个数组,这个数组记录了他学习c++ 语言的过程. 现在这个数组a里有一些字符,第i个字符的数量是a[i].巨巨想用这些字符来构造一些回文串好让他的程序通过编译. 他 ...
- test20181018 B君的第三题
题意 B 君的第三题(shenyang) 题目描述 客似云来,万里无云 B 君得到了一个数组\(\{a_1,a_2,\dots,a_n\}\). B 君想通过修改让数组中个每对数都互质. 每次使一个数 ...
- 【转】在Visual Studio中怎样快速添加代码段
原文网址:http://blog.csdn.net/yl2isoft/article/details/9735527 以前一直只知道,键入prop,再按两次tab键,会生成自动属性代码. 今天闲着无事 ...
- ffmpeg C++程序编译时报__cxa_end_catch错误
解决方法在编译sh中加上 -lsupc++ 即可. 2.STL模块函数找不到,链接失败stdc++/include/bits/stl_list.h:466: error: undefined refe ...