• Shiro【内置Realm实操】


    一、前言

    Shiro【初识】中我们已经知道 Realm 主要是用来从数据库中获取用户、角色、资源等数据的。

    但 Shiro 还给我们提供了很多 Realm,让我们可以操作其他的数据源,比如配置文件等等。

    二、项目环境

    本文中的项目使用环境为:JDK8 + Maven 3.6.3 + SpringBoot 2.4.1 + Shiro 1.4.0 + Druid 1.1.6

    项目依赖如下:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>1.4.0</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.6</version>
    </dependency>
    

    三、Shiro内置 IniRealm 实操

    类路径下有如下配置文件:

    shiro.ini

    # 格式 name=password,role1,role2,..roleN
    [users]
    jack = 456, user
    zhangsan = 123, root, admin
    
    # 格式 role=permission1,permission2...permissionN   也可以用通配符
    # 下面配置user的权限为所有video:find,video:buy,如果需要配置video全部操作crud 则 user = video:*
    [roles]
    user = video:find,video:buy
    visitor = good:find,good:add
    
    # 'admin' role has all permissions, indicated by the wildcard '*'
    admin = *
    

    测试类的代码如下:

    /**
     * 测试 IniRealm 的使用:从ini格式的文件中获取用户、角色、资源(权限)
     */
    public class IniRealmTest {
    
        @Test
        public void test(){
            // 创建SecurityManager工厂,通过配置文件ini创建
            Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
            SecurityManager securityManager = factory.getInstance();
    
            // 构造SecurityManager环境
            SecurityUtils.setSecurityManager(securityManager);
    
            Subject subject = SecurityUtils.getSubject();
            UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack", "456");
    
            subject.login(usernamePasswordToken);
    
            // 判断是否认证成功
            System.out.println(" 认证结果:"+subject.isAuthenticated());
    
            // 判断是否有对应角色
            System.out.println(" 是否有对应的user角色:"+subject.hasRole("user"));
    
            // 获取账号
            System.out.println(" getPrincipal=" + subject.getPrincipal());
    
            // 检查是否有指定角色(无返回值)
            subject.checkRole("user");
    
            // 检查是否有指定权限(无返回值)
            subject.checkPermission("video:find");
    
            // 检查是否有指定权限(有返回值)
            System.out.println( "是否有video:find 权限:"+ subject.isPermitted("video:find"));
    
            subject.logout();
    
            System.out.println("logout后认证结果:"+subject.isAuthenticated());
        }
    }
    

    四、Shiro内置 JdbcRealm 实操

    (一)方式一

    类路径下有如下配置文件:

    jdbcrealm.ini

    #注意 文件格式必须为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/shiro_test?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
    
    dataSource.username=root
    dataSource.password=root
    
    #指定数据源
    jdbcRealm.dataSource=$dataSource
    
    #开启查找权限
    jdbcRealm.permissionsLookupEnabled=true
    
    #指定SecurityManager的Realms实现,设置realms,可以有多个,用逗号隔开
    securityManager.realms=$jdbcRealm
    

    数据库中表的格式、字段名称、关联关系一定要按照 Shiro 的格式进行创建,否则会报错。

    其SQL脚本如下:

    DROP TABLE IF EXISTS `roles_permissions`;
    
    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 DEFAULT CHARSET=utf8;
    
    LOCK TABLES `roles_permissions` WRITE;
    /*!40000 ALTER TABLE `roles_permissions` DISABLE KEYS */;
    
    INSERT INTO `roles_permissions` (`id`, `role_name`, `permission`)
    VALUES
    	(4,'admin','video:*'),
    	(3,'role1','video:buy'),
    	(2,'role1','video:find'),
    	(5,'role2','*'),
    	(1,'root','*');
    
    /*!40000 ALTER TABLE `roles_permissions` ENABLE KEYS */;
    UNLOCK TABLES;
    
    
    DROP TABLE IF EXISTS `user_roles`;
    
    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 DEFAULT CHARSET=utf8;
    
    LOCK TABLES `user_roles` WRITE;
    /*!40000 ALTER TABLE `user_roles` DISABLE KEYS */;
    
    INSERT INTO `user_roles` (`id`, `username`, `role_name`)
    VALUES
    	(1,'jack','role1'),
    	(2,'jack','role2'),
    	(4,'xdclass','admin'),
    	(3,'xdclass','root');
    
    /*!40000 ALTER TABLE `user_roles` ENABLE KEYS */;
    UNLOCK TABLES;
    
    
    DROP TABLE IF EXISTS `users`;
    
    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 DEFAULT CHARSET=utf8;
    
    LOCK TABLES `users` WRITE;
    /*!40000 ALTER TABLE `users` DISABLE KEYS */;
    
    INSERT INTO `users` (`id`, `username`, `password`, `password_salt`)
    VALUES
    	(1,'jack','123',NULL),
    	(2,'xdclass','456',NULL);
    
    /*!40000 ALTER TABLE `users` ENABLE KEYS */;
    UNLOCK TABLES;
    

    测试类的代码如下:

    /**
     * 测试 JdbcRealm 的使用:从数据库中获取用户、角色、资源(权限)
     * 其实都是将数据获取到 Realm 对象中,只不过该种方式是通过 ini 文件的方式获取数据库信息从而获取数据
     */
    public class JdbcRealmTest01 {
    
        @Test
        public void test() {
            //创建SecurityManager工厂,通过配置文件ini创建
            IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:jdbcrealm.ini");
    
            // 构造SecurityManager环境
            SecurityManager securityManager = factory.getInstance();
            SecurityUtils.setSecurityManager(securityManager);
    
            Subject subject = SecurityUtils.getSubject();
    
            //用户输入的账号密码
            UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack", "123");
    
            subject.login(usernamePasswordToken);
    
            System.out.println(" 认证结果:"+subject.isAuthenticated());
    
            System.out.println(" 是否有对应的role1角色:"+subject.hasRole("role1"));
    
            System.out.println(" 是否有video:find权限:"+ subject.isPermitted("video:find"));
        }
    }
    
    (二)方式二
    /**
     * 测试 JdbcRealm 的使用:从数据库中获取用户、角色、资源(权限)
     * 其实都是将数据获取到 Realm 对象中,只不过该种方式是通过连接池的方式获取数据库信息从而获取数据
     */
    public class JdbcRealmTest02 {
    
        @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/shiro_test?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false");
            ds.setUsername("root");
            ds.setPassword("root");
    
            JdbcRealm jdbcRealm = new JdbcRealm();
            // 开启查找权限
            jdbcRealm.setPermissionsLookupEnabled(true);
            jdbcRealm.setDataSource(ds);
    
            securityManager.setRealm(jdbcRealm);
    
            //将securityManager 设置到当前运行环境中
            SecurityUtils.setSecurityManager(securityManager);
    
            Subject subject = SecurityUtils.getSubject();
    
            //用户输入的账号密码
            UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack", "123");
    
            subject.login(usernamePasswordToken);
    
            System.out.println(" 认证结果:"+subject.isAuthenticated());
    
            System.out.println(" 是否有对应的role1角色:"+subject.hasRole("role1"));
    
            System.out.println(" 是否有video:find权限:"+ subject.isPermitted("video:find"));
    
            System.out.println(" 是否有任意权限:"+ subject.isPermitted("aaaa:xxxxxxxxx"));
        }
    }
    

    Java新手,若有错误,欢迎指正!

  • 相关阅读:
    mmsplayer V2 for android 抢先发布
    mmsplayer v2 windows C 之(mmsplayer_wave )
    mmsplayer v2 java 之(MmsplayerActivity Activity类)
    mmsplayer V2 for windows 发布
    今天休息,明天晚上继续IOS版本mmsplayer V2
    mmsplayer v2 java 之(MmsplayerActivity Activity类)
    mmsplayer V2 for windows 发布
    自定义函数:删除数组B中与数组A重复的值
    LotusScript方法扩展
    MS SQL 2005 SP2新功能
  • 原文地址:https://www.cnblogs.com/Java-biao/p/14480673.html
Copyright © 2020-2023  润新知