shiro框架学习-4- Shiro内置JdbcRealm
1. JdbcRealm 数据库准备
JdbcRealm就是用户的角色,权限都从数据库中读取,也就是用来进行用户认证授权的安全数据源更换为从数据库中读取,其他没有差别,首先在数据库创建三张表:
CREATE TABLE `users` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`username` varchar(100) DEFAULT NULL,
`password` varchar(100) DEFAULT NULL,
`password_salt` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_users_username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
CREATE TABLE `user_roles` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`username` varchar(100) DEFAULT NULL,
`role_name` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_user_roles` (`username`,`role_name`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
CREATE TABLE `roles_permissions` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`role_name` varchar(100) DEFAULT NULL,
`permission` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_roles_permissions` (`role_name`,`permission`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
插入数据:
INSERT INTO `users` VALUES (1,'jack','123',NULL),(2,'xdclass','456',NULL);
INSERT INTO `roles_permissions` VALUES (4,'admin','video:*'),(3,'role1','video:buy'),(2,'role1','video:find'),(5,'role2','*'),(1,'root','*');
INSERT INTO `user_roles` VALUES (1,'jack','role1'),(2,'jack','role2'),(4,'xdclass','admin'),(3,'xdclass','root');
2. JdbcRealm 配置文件
#注意 文件格式必须为ini,编码为ANSI
#声明Realm,指定realm类型
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm #配置数据源
#dataSource=com.mchange.v2.c3p0.ComboPooledDataSource
dataSource=com.alibaba.druid.pool.DruidDataSource # mysql-connector-java 5 用的驱动url是com.mysql.jdbc.Driver,mysql-connector-java6以后用的是com.mysql.cj.jdbc.Driver
dataSource.driverClassName=com.mysql.cj.jdbc.Driver #避免安全警告
dataSource.url=jdbc:mysql://localhost:3306/xdclass_shiro?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
dataSource.username=root
dataSource.password=lchadmin #指定数据源
jdbcRealm.dataSource=$dataSource #开启查找权限,否则不会自动查询角色对应的权限,造成实际有权限,调用subject.isPermitted()返回false
jdbcRealm.permissionsLookupEnabled=true #指定SecurityManager的Realms实现,设置realms,可以有多个,用逗号隔开
securityManager.realms=$jdbcRealm
测试代码
package net.xdclass.xdclassshiro; import com.alibaba.druid.pool.DruidDataSource;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Test; /**
* jdbcRealm操作
*/
public class QuicksStratTest5_3 { @Test
public void testAuthentication() {
//通过配置文件创建SecurityManager工厂
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:jdbcrealm.ini");
// 获取SecurityManager实例
SecurityManager securityManager = factory.getInstance();
//设置当前上下文
SecurityUtils.setSecurityManager(securityManager); //获取当前subject(application应用的user)
Subject subject = SecurityUtils.getSubject();
// 模拟用户输入
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack","123");
//
subject.login(usernamePasswordToken);
System.out.println("认证结果(是否已授权):" + subject.isAuthenticated());
//最终调用的是org.apache.shiro.authz.ModularRealmAuthorizer.hasRole方法
System.out.println("是否有role1角色:" + subject.hasRole("role1"));
System.out.println("是否有role2角色:" + subject.hasRole("role2"));
System.out.println("是否有root角色:" + subject.hasRole("root"));
//获取登录 账号
System.out.println("getPrincipal():" + subject.getPrincipal());
//校验角色,没有返回值,校验不通过,直接跑出异常
subject.checkRole("role1");
System.out.println("=======subject.checkRole(\"role1\") passed=====" );
// user jack有video的find权限,执行通过
subject.checkPermission("video:find");
// 是否有video:find权限:true
System.out.println("是否有video:find权限:" + subject.isPermitted("video:find"));
// 是否有video:delete权限:false
System.out.println("是否有video:delete权限:" + subject.isPermitted("video:delete"));
//user jack没有video的删除权限,执行会报错:org.apache.shiro.authz.UnauthorizedException: Subject does not have permission [video:delete]
subject.checkPermission("video:delete");
subject.logout();
System.out.println("logout后认证结果:" + subject.isAuthenticated()); /* org.apache.shiro.realm.jdbc.JdbcRealm源码
* 1. class JdbcRealm extends AuthorizingRealm
* 2. 预置了默认的查询语句,因此创建数据库时字段名字要与这里定义的一致!!!
* protected static final String DEFAULT_AUTHENTICATION_QUERY = "select password from users where username = ?";
protected static final String DEFAULT_SALTED_AUTHENTICATION_QUERY = "select password, password_salt from users where username = ?";
#根据用户名称查角色
protected static final String DEFAULT_USER_ROLES_QUERY = "select role_name from user_roles where username = ?";
* #根据用户名称查权限
protected static final String DEFAULT_PERMISSIONS_QUERY = "select permission from roles_permissions where role_name = ?";
protected String authenticationQuery = "select password from users where username = ?";
protected String userRolesQuery = "select role_name from user_roles where username = ?";
* #根据角色查询权限
protected String permissionsQuery = "select permission from roles_permissions where role_name = ?";
*
* 3. protected boolean permissionsLookupEnabled = false; 这个开关默认是关闭的,需要手动打开
* 4.
* protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
if (principals == null) {
throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
} else {
String username = (String)this.getAvailablePrincipal(principals);
Connection conn = null;
Set<String> roleNames = null;
Set permissions = null; try {
conn = this.dataSource.getConnection();
roleNames = this.getRoleNamesForUser(conn, username);
if (this.permissionsLookupEnabled) {
permissions = this.getPermissions(conn, username, roleNames);
}
} catch (SQLException var11) {
String message = "There was a SQL error while authorizing user [" + username + "]";
if (log.isErrorEnabled()) {
log.error(message, var11);
} throw new AuthorizationException(message, var11);
} finally {
JdbcUtils.closeConnection(conn);
} SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleNames);
info.setStringPermissions(permissions);
return info;
}
* */
} @Test
public void test2(){
// 不使用配置文件的情况下:
DefaultSecurityManager securityManager = new DefaultSecurityManager();
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/xdclass_shiro?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false");
ds.setUsername("root");
ds.setPassword("lchadmin");
JdbcRealm jdbcRealm = new JdbcRealm();
jdbcRealm.setPermissionsLookupEnabled(true);
jdbcRealm.setDataSource(ds);
securityManager.setRealm(jdbcRealm);
// 将securityManager设置到当前运行环境中
SecurityUtils.setSecurityManager(securityManager);
//获取当前subject(application应用的user)
Subject subject = SecurityUtils.getSubject();
// 模拟用户输入
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack","123");
//
subject.login(usernamePasswordToken);
System.out.println("认证结果(是否已授权):" + subject.isAuthenticated());
//最终调用的是org.apache.shiro.authz.ModularRealmAuthorizer.hasRole方法
System.out.println("是否有role1角色:" + subject.hasRole("role1"));
System.out.println("是否有role2角色:" + subject.hasRole("role2"));
System.out.println("是否有root角色:" + subject.hasRole("root"));
//获取登录 账号
System.out.println("getPrincipal():" + subject.getPrincipal());
//校验角色,没有返回值,校验不通过,直接抛出异常
subject.checkRole("role1");
System.out.println("=======subject.checkRole(\"role1\") passed=====" );
// user jack有video的find权限,执行通过
subject.checkPermission("video:find");
// 是否有video:find权限:true
System.out.println("是否有video:find权限:" + subject.isPermitted("video:find"));
// 是否有video:delete权限:false
System.out.println("是否有video:delete权限:" + subject.isPermitted("video:delete"));
//user jack没有video的删除权限,执行会报错:org.apache.shiro.authz.UnauthorizedException: Subject does not have permission [video:delete]
subject.checkPermission("video:delete");
} }
shiro框架学习-4- Shiro内置JdbcRealm的更多相关文章
- shiro框架学习-3- Shiro内置realm
1. shiro默认自带的realm和常见使用方法 realm作用:Shiro 从 Realm 获取安全数据 默认自带的realm:idae查看realm继承关系,有默认实现和自定义继承的realm ...
- shiro框架学习-6-Shiro内置的Filter过滤器及数据加解密
1. shiro的核心过滤器定义在枚举类DefaultFilter 中,一共有11个 ,配置哪个路径对应哪个拦截器进行处理 // // Source code recreated from a .c ...
- shiro框架学习-5-自定义Realm
1. 自定义Realm基础 步骤: 创建一个类 ,继承AuthorizingRealm->AuthenticatingRealm->CachingRealm->Realm 重写授权方 ...
- shiro框架学习-1-shiro基本概念
1. 什么是权限控制 基本上涉及到用户参与的系统都要进行权限管理,权限管理属于系统安全的范畴,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户可以访问而且只能访问自己被授权的资源, ...
- Python学习第二阶段day1 内置函数,序列化,软件目录开发规范
内置函数 1.abs() 求绝对值 2.all() 所有元素为真才返回真 all( [1,1,2,3,-1] ) 值为True 3.any() 所有元素为假才返回假 any([0,0,0 ...
- shiro基础学习(二)—shiro认证
一.shiro简介 shiro是apache旗下一个开源框架,它将软件系统的安全认证相关的功能抽取出来,实现用户身份认证.权限授权.加密.会话管理等功能,组成了一个通用的安全认证框架. 以下 ...
- python自动化测试学习笔记-4内置函数,处理json
函数.全局变量 写代码时注意的几点事项: 1.一般写代码的时候尽量少用或不用全局变量,首先全局变量不安全,大家协作的情况下,代码公用容易被篡改,其次全局变量会一直占用系统内容. 2.函数里如果有多个r ...
- js学习---常用的内置对象(API)小结 :
内置对象(API): 日期 Date: getFullYear() 返回完整的4位的年份 如:2016 getMonth() 返回月份,从0开始 getDate() 返回当前月的第几天,当 ...
- 学习笔记——Maven 内置变量
Maven内置变量说明: ${basedir} 项目根目录(即pom.xml文件所在目录) ${project.build.directory} 构建目录,缺省为target目录 ${project. ...
随机推荐
- [ASP.NET] [JS] GridView点击高亮当前选择行,并在点击另一行时恢复上一选择行背景颜色
在ASP.NET中的gridview控件里面可以通过设定其OnRowDataBound事件来进行实现高亮当前行的操作 前端控件的设置: 只要设置好OnRowDataBound属性即可,会自动在.cs文 ...
- zabbix监控java
参考: 官网: https://www.zabbix.com/documentation/4.0/manual/config/items/itemtypes/jmx_monitoring
- Linux下面MariaDB 管理命令基础使用
MariaDB 是 MySQL 的一个分,由于某些原因,使之取代了Mysql成为了 RHEL/CentOS 7 的默认数据库.针对数据库的操作我们经常做的操作就是增删查改,接下来就介绍下 MariaD ...
- 史上最详细 Linux 用户与用户组知识
1.用户和用户组文件 在 linux 中,用户帐号,用户密码,用户组信息和用户组密码均是存放在不同的配置文件中的. 在 linux 系统中,所创建的用户帐号和其相关信息 (密码除外) 均是存放在 / ...
- CF 11D A Simple Task 题解
题面 这道题的数据范围一看就是dfs或状压啦~ 本文以状压的方式来讲解 f[i][j]表示目前的节点是i,已经经历过的节点的状态为j的简单环的个数: 具体的转移方程和细节请看代码: PS:(i& ...
- 记一次程序从x86_64linux平台移植到armv7平台
前言 最近接了个任务,需要把代码移植到armv7平台,搜寻相关方法,了解到可以利用交叉编译工具如:gcc-linaro-arm-linux-gnueabihf.把自己依赖的第三方库代码和自己代码分别编 ...
- 【MQ】为什么选择RocketMQ?
一.前言 提到mq,可能很多朋友都有多耳闻,很多大公司都在使用这种技术.就小编而言,听说使用mq可以进行秒杀的操作,而且使用十分的方便,效率十分的高.以前小编也做过关于秒杀的技术,就是使用悲观锁对DA ...
- centos7配置mysql8.0主从复制
注意:1.主库:10.1.131.75,从库:10.1.131.762.server-id必须是纯数字,并且主从两个server-id在局域网内要唯一. [主节点]vi /etc/my.cnf[mys ...
- springboot导包spring-boot-starter-parent出现错误
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot ...
- G1 垃圾收集器之对象分配过程
G1的年轻代由eden region 和 survivor region 两部分组成,新建的对象(除了巨型对象)大部分都在eden region中分配内存,如果分配失败,说明eden region已经 ...