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");
    }

}

原文地址:https://www.cnblogs.com/enjoyjava/p/12079743.html

时间: 2024-10-10 06:45:44

shiro框架学习-4- Shiro内置JdbcRealm的相关文章

python学习笔记11-python内置函数

python学习笔记11-python内置函数 一.查看python的函数介绍: https://docs.python.org/2/library/ 二.python内置函数 1.abs获取绝对值: 通过python官网查看abs abs(x) Return the absolute value of a number. The argument may be a plain or long integer or a floating point number. If the argument

php学习之重要内置函数

1. require_once()函数 此函数在脚本执行期间包含并执行指定的文件,与require语句类似,唯一区别是如果该文件中的代码已经被包含了,则不会再次包含. require_once()函数保证在脚本执行期间,对于可能出现相同的文件被包含超过一次的 情况下,想确保它包含一次以避免函数重定义,变量重新赋值等问题. 与include()函数一样,此函数执行成功则返回true. 同时,我们要注意到在类似window这样的对大小写不敏感的操作系统中,require_once()和include

shiro框架学习-3- Shiro内置realm

1. shiro默认自带的realm和常见使用方法 realm作用:Shiro 从 Realm 获取安全数据 默认自带的realm:idae查看realm继承关系,有默认实现和自定义继承的realm 两个概念 principal : 主体的标示,可以有多个,但是需要具有唯一性,常见的有用户名,手机号,邮箱等 credential:凭证, 一般就是密码 所以一般我们说 principal + credential 就账号 + 密码 开发中,往往是自定义realm , 即集成 Authorizing

shiro框架学习-6-Shiro内置的Filter过滤器及数据加解密

1.  shiro的核心过滤器定义在枚举类DefaultFilter 中,一共有11个 ,配置哪个路径对应哪个拦截器进行处理 // // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package org.apache.shiro.web.filter.mgt; import java.util.LinkedHashMap; import ja

js学习---常用的内置对象(API)小结 :

内置对象(API): 日期 Date: getFullYear() 返回完整的4位的年份  如:2016 getMonth()    返回月份,从0开始 getDate()   返回当前月的第几天,当月的几号 getHours()   返回0-23的小时数字 getMinutes()  返回0-59的分钟数字 getSeconds()  返回0-59的秒数字 getTime()    返回毫秒数 getMilliseconds()  返回毫秒数字 getDay()       返回星期几 Arr

python学习系列--python内置函数(一)

先列出所有的python内置函数,可以看到还是挺多的. abs()        求给定数的绝对值. all()          传入一个列表,只有当列表中所有元素都是真时,该函数返回真. any()        传入一个列表,只要列表中有一个元素为真,该函数即返回真. ascii()       执行对象中的__repr__方法.该函数在python2.7中已弃用. bin()         将给定的值转换成二进制. bool()       判断真假. bytearray()     

Python学习笔记-Day3-python内置函数

python内置函数 1.abs    求绝对值 2.all 判断迭代器中的所有数据是否都为true 如果可迭代的数据的所有数据都为true或可迭代的数据为空,返回True.否则返回False 3.any 判断迭代器中的是否有一个数据为true 如果可迭代的数据中有一个数据为true,返回True.否则返回False.可迭代的数据为空也返回False 4.bin    转换整数为一个二进制字符串(其他数据类型报错) 5.bool 转换一个数据为布尔值 bool是int的子类,如果参数为false

jsp 学习笔记 1——内置对象

jsp 内置对象 jsp中,有9大内置对象有: 1)out. 2)request. 3)response.4)session.5)application; //常用 6)page 7)pageContext 8)exception 9)config //不太常用 一.requset & response 对象 用>>> request >>>web 户<<< response <<<服务器, 由用户向服务器发送 称为请求(re

老男孩学习 python 5 内置函数和文件操作

lambda 表达式: 内置函数: ABS:绝对值: ALL:循环参数,如果每个元素都为真,那么all的返回的值为真 ANY 只有一个真,则为真 ASCII ,利用对象中_repr_,获得返回值: INT: 将别的进制的数据转换十进制的数据: bin:将字符串转换成字节 bool  判断真假,把一个对象转换成布尔值 CHR:将10进制的数据转换成ASCII中的字母 ord:将ascii中的字符转换成十进制的字符 radmon 模块 random.randrange(1.8) 从1到8中生成随机数