• 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"); } }
  • 相关阅读:
    mysql TO_DAYS()函数
    MySQL year函数
    protobuff java 包编译(Windows)
    苹果笔记本只有电源键能用的解决办法
    linux普通用户获取管理员权限
    linux用户管理
    基于ASIHTTPRequest封装的HttpClient
    Object-C 多线程中锁的使用-NSLock
    appstore 上传需要的icon
    iPhone之IOS5内存管理(ARC技术概述)
  • 原文地址:https://www.cnblogs.com/enjoyjava/p/12079743.html
Copyright © 2020-2023  润新知