[转] Shiro权限控制框架入门1:Shiro的认证流程以及基本概念介绍

简介

Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码学和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序

Shiro的三个核心组件:Subject,、SecurityManager 以及 Realms

  • Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。但考虑到大多数目的和用途,你可以把它认为是Shiro的“用户”概念。Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作

  • SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务

  • Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。

注:上面的介绍参考至百度百科

Shiro的认证流程以及基本概念介绍

(1)第一个入门实例:

    /**
     * 第一个实例
     * 参考:http://jinnianshilongnian.iteye.com/blog/2019547
     * */
    @Test
    public void testHello(){
        //1 获取SecurityManager工厂
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:cn/zifangsky/test/shiro/base/shiro.ini");
        
        //2  获取SecurityManager实例,并绑定给SecurityUtils
        SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);
        
        //3 获取Subject,创建用户名/密码验证Token
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("admin", "admin");
        
        try {
            //4 登录,即:身份认证
            subject.login(token);
            System.out.println("登录认证成功");
        } catch (AuthenticationException e) {
            //5 认证失败
            System.err.println("认证失败");
        }
        
        //6 退出登录
        subject.logout();
    }

注:这里为了方便使用了JUnit单元测试。也就是说需要在此次测试的项目中引入junit-4.10.jar这个jar包,同时需要在你的类上添加@RunWith(JUnit4.class)这个注解,比如说这样:

@RunWith(JUnit4.class)
public class Helloworld {
}

同时,上面用到的shiro.ini这个配置文件是这样的:

[users]  
admin=admin
test=123456

(2)自定义Realm:
关于Realm这个类,当需要对用户执行认证(登录)和授权(访问控制)验证时,Shiro都会从应用配置的Realm中查找用户信息以及权限信息。因此,我们可以自定义一个Realm以实现自定义登录认证和权限控制,下面我将用一个简单例子介绍通过自定义Realm实现自定义认证(PS:关于自定义授权相关内容放到下一篇文章中叙述):

i)自定义的CustomRealm.java:

package cn.zifangsky.test.shiro.base;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.realm.Realm;

public class CustomRealm implements Realm {
    /**
     * 返回一个唯一的Realm名称
     * */
    @Override
    public String getName() {
        return "CustomRealm";
    }

    /**
     * 判断此Realm是否支持此Token
     * */
    @Override
    public boolean supports(AuthenticationToken token) {
        //仅支持UsernamePasswordToken类型的Token
        return token instanceof UsernamePasswordToken;
    }
    
    /**
     * 自定义认证
     * */
    @Override
    public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //根据token获取需要认证的信息(登录时输入的信息)
        String username = (String) token.getPrincipal();  //获取用户名
        String password = String.valueOf((char[])token.getCredentials());  //获取密码
        
        if(!"test".equals(username))
            throw new UnknownAccountException();
        if(!"123456".equals(password))
            throw new IncorrectCredentialsException();
        
        return new SimpleAuthenticationInfo(username, password, getName());
    }
}

ii)对应的配置文件shiro-realm.ini:

#申明一个自定义的Realm
customRealm=cn.zifangsky.test.shiro.base.CustomRealm
#指定securityManager的realms实现
securityManager.realms=$customRealm

iii)测试方法:

    /**
     * 测试自定义Realm
     * */
    @Test
    public void testCustomRealm(){
        //1 获取SecurityManager工厂
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:cn/zifangsky/test/shiro/base/shiro-realm.ini");
        
        //2  获取SecurityManager实例,并绑定给SecurityUtils
        SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);
        
        //3 获取Subject,创建用户名/密码验证Token
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("test", "123456");
        try {
            //4 登录,即:身份认证
            subject.login(token);
            System.out.println("登录认证成功");
        } catch (AuthenticationException e) {
            //5 认证失败
            System.err.println("认证失败");
        }
        
        //6 退出登录
        subject.logout();
    }

关于这个测试方法,除了使用了一个不同的ini配置文件之外,其余部分都跟上面那个例子是一样的,因此这里就不多说了.

(3)使用数据库的shiro登录认证:

在上面的两个例子中都没有使用到数据库,同时登录认证的账号密码都硬编码地配置到ini配置文件中了。但是实际的开发中是不可能将用户信息这样硬编码的,因此接下来我将介绍基于数据库的shiro登录认证:

i)测试使用的SQL语句:

我在这里测试时使用的数据库是MySQL,测试使用的SQL语句是:

-- ----------------------------
-- Table structure for roles_permissions
-- ----------------------------
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 AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of roles_permissions
-- ----------------------------
INSERT INTO `roles_permissions` VALUES ('1', 'admin', '/');

-- ----------------------------
-- Table structure for users
-- ----------------------------
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 AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of users
-- ----------------------------
INSERT INTO `users` VALUES ('1', 'admin', '123456', null);

-- ----------------------------
-- Table structure for user_roles
-- ----------------------------
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 AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user_roles
-- ----------------------------
INSERT INTO `user_roles` VALUES ('1', 'admin', 'admin');

注:在基于ini配置文件的配置时,如果不手动改写shiro的查询语句,那么shiro在进行认证和授权时默认会查询上面的这几个表

ii)配置文件shiro-jdbc-realm.ini:

jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
dataSource=com.alibaba.druid.pool.DruidDataSource
dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql://localhost:3306/shiro
dataSource.username=root
dataSource.password=root
jdbcRealm.dataSource=$dataSource
securityManager.realms=$jdbcRealm

这里的配置也很简单,先是定义了一个JDBC的Realm,接着定义了一个数据源以及它的一些基本配置。需要注意的是我这里使用的是druid连接池,如果要使用这个连接池的话需要引入druid-1.0.26.jar这个jar包。当然,这里也可以使用其他的一些连接池或者基本的jdbc数据源

iii)测试方法:

    /**
     * 测试JDBC Realm
     * */
    @Test
    public void testJdbcRealm(){
        //1 获取SecurityManager工厂
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:cn/zifangsky/test/shiro/base/shiro-jdbc-realm.ini");
        
        //2  获取SecurityManager实例,并绑定给SecurityUtils
        SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);
        
        //3 获取Subject,创建用户名/密码验证Token
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456");
        try {
            //4 登录,即:身份认证
            subject.login(token);
            System.out.println("登录认证成功");
        } catch (AuthenticationException e) {
            //5 认证失败
            System.err.println("认证失败");
        }
        
        //6 退出登录
        subject.logout();
    }

很显然,运行这个方法也是可以登录成功的,输出结果略

(4)用户拥有的角色、权限判断:

package cn.zifangsky.test.shiro.func;

import java.util.Arrays;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)
public class RoleTest {
    /**
     * 粒度大,如果某种角色不存在了则需要删除所有的用户对应的角色信息
     * */
    @Test
    public void testHasRole() {
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:cn/zifangsky/test/shiro/func/shiro-role.ini");

        SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);

        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("admin", "admin");

        subject.login(token);

        System.out.println(subject.hasRole("role1"));
        System.out.println(subject.hasAllRoles(Arrays.asList("role1", "role2")));
        boolean[] results = subject.hasRoles(Arrays.asList("role1", "role2", "role3"));
        System.out.println("results[0]: " + results[0]);
        System.out.println("results[1]: " + results[1]);
        System.out.println("results[2]: " + results[2]);
        
//      subject.checkRole("role3");
    }
    
    /**
     * 粒度小,如果某种角色不存在了只需要删除该角色即可
     * */
    @Test
    public void testIsPermitted(){
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:cn/zifangsky/test/shiro/func/shiro-permission.ini");

        SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);

        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("admin", "admin");

        subject.login(token);
        
        System.out.println(subject.isPermitted("user:create"));
        System.out.println(subject.isPermittedAll("user:create","user:delete"));
    }

}

这里测试所用的两个ini配置文件分别是:

i)shiro-role.ini:

[users]  
admin=admin,role1,role2
test=123456,role1

其格式是:

用户名=密码,角色1,角色2 …

ii)shiro-permission.ini:

[users]  
admin=admin,role1,role2
test=123456,role1
[roles]
role1=user:create
role2=user:create,user:update
role3=user:create,update,delete
role4=user:*
role5=*:view

这里的格式跟上面的差不多,不同的是星号表示任意,例如:role4=user:* 表示role4这个角色拥有user的所有权限。

上面的例子最后输出如下:

方法一:

true
true
results[0]: true
results[1]: true
results[2]: false

方法二:

true
false

基于角色的访问控制(Role-Based Access Control)

基于角色的访问控制简称:RBAC。在本篇文章的末尾补充介绍一点目前最常用也是最基本的权限控制模型,也就是基于角色的访问控制。

基于RBAC的权限管理,其实体关系大致是这样的:

因为用户与角色之间的关系是多对多的,角色与权限之间的关系也是多对多的。因此分别建立了用户角色关联表角色权限关联表分别存放用户与角色之间、角色与权限之间的对应关系。测试的数据库表如下:

DROP TABLE IF EXISTS `usr_func`;
CREATE TABLE `usr_func` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) DEFAULT NULL,
  `description` varchar(100) DEFAULT NULL,
  `code` varchar(100) DEFAULT NULL,
  `url` varchar(200) DEFAULT NULL,
  `status` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of usr_func
-- ----------------------------
INSERT INTO `usr_func` VALUES ('1', '用户管理-查询', null, 'YHGL:CX', null, 'enable');
INSERT INTO `usr_func` VALUES ('2', '用户管理-新增', null, 'YHGL:XZ', null, 'enable');
INSERT INTO `usr_func` VALUES ('3', '用户管理-编辑', null, 'YHGL:BJ', null, 'enable');
INSERT INTO `usr_func` VALUES ('4', '用户管理-停用', null, 'YHGL:TY', null, 'enable');
INSERT INTO `usr_func` VALUES ('5', '用户管理-启用', null, 'YHGL:QY', null, 'enable');
INSERT INTO `usr_func` VALUES ('6', '用户管理-删除', null, 'YHGL:SC', null, 'enable');
INSERT INTO `usr_func` VALUES ('7', '文章管理-查询', null, 'WZGL:CX', null, 'enable');
INSERT INTO `usr_func` VALUES ('8', '文章管理-新增', null, 'WZGL:XZ', null, 'enable');
INSERT INTO `usr_func` VALUES ('9', '文章管理-编辑', null, 'WZGL:BJ', null, 'enable');
INSERT INTO `usr_func` VALUES ('10', '文章管理-删除', null, 'WZGL:SC', null, 'enable');

-- ----------------------------
-- Table structure for usr_role
-- ----------------------------
DROP TABLE IF EXISTS `usr_role`;
CREATE TABLE `usr_role` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `roleName` varchar(100) DEFAULT NULL,
  `description` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of usr_role
-- ----------------------------
INSERT INTO `usr_role` VALUES ('1', 'manager', '管理员');
INSERT INTO `usr_role` VALUES ('2', 'editor', '编辑');
INSERT INTO `usr_role` VALUES ('3', 'author', '作者');
INSERT INTO `usr_role` VALUES ('4', 'subscriber', '订阅者');
INSERT INTO `usr_role` VALUES ('5', 'contributor', '投稿者');

-- ----------------------------
-- Table structure for usr_role_func
-- ----------------------------
DROP TABLE IF EXISTS `usr_role_func`;
CREATE TABLE `usr_role_func` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `roleId` int(11) DEFAULT NULL,
  `funcId` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `roleId` (`roleId`),
  CONSTRAINT `roleId` FOREIGN KEY (`roleId`) REFERENCES `usr_role` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of usr_role_func
-- ----------------------------
INSERT INTO `usr_role_func` VALUES ('1', '1', '1');
INSERT INTO `usr_role_func` VALUES ('2', '1', '2');
INSERT INTO `usr_role_func` VALUES ('3', '1', '3');
INSERT INTO `usr_role_func` VALUES ('4', '1', '4');
INSERT INTO `usr_role_func` VALUES ('5', '1', '5');
INSERT INTO `usr_role_func` VALUES ('6', '1', '6');
INSERT INTO `usr_role_func` VALUES ('7', '1', '7');
INSERT INTO `usr_role_func` VALUES ('8', '1', '8');
INSERT INTO `usr_role_func` VALUES ('9', '1', '9');
INSERT INTO `usr_role_func` VALUES ('10', '1', '10');
INSERT INTO `usr_role_func` VALUES ('11', '2', '7');
INSERT INTO `usr_role_func` VALUES ('12', '2', '8');
INSERT INTO `usr_role_func` VALUES ('13', '2', '9');
INSERT INTO `usr_role_func` VALUES ('14', '2', '10');
INSERT INTO `usr_role_func` VALUES ('15', '3', '7');
INSERT INTO `usr_role_func` VALUES ('16', '3', '8');
INSERT INTO `usr_role_func` VALUES ('17', '3', '9');
INSERT INTO `usr_role_func` VALUES ('18', '4', '7');
INSERT INTO `usr_role_func` VALUES ('19', '5', '8');

-- ----------------------------
-- Table structure for usr_user
-- ----------------------------
DROP TABLE IF EXISTS `usr_user`;
CREATE TABLE `usr_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(100) DEFAULT NULL,
  `password` varchar(256) DEFAULT NULL,
  `mobile` varchar(30) DEFAULT NULL,
  `email` varchar(100) DEFAULT NULL,
  `createTime` datetime DEFAULT NULL,
  `updateTime` datetime DEFAULT NULL,
  `channelId` int(11) DEFAULT NULL,
  `status` varchar(20) DEFAULT '1',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of usr_user
-- ----------------------------
INSERT INTO `usr_user` VALUES ('1', 'admin', '8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918', '110', 'admin@zifangsky.cn', '2016-10-04 10:33:23', '2016-10-06 10:38:40', '1', 'enable');
INSERT INTO `usr_user` VALUES ('2', 'test', '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92', '3456789', 'test@110.com', '2016-10-18 18:25:12', '2016-10-19 18:25:17', '2', 'enable');
INSERT INTO `usr_user` VALUES ('5', 'zifangsky', '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92', '911', 'admin@zifangsky.cn', '2016-10-20 11:46:45', '2016-10-20 11:46:57', '1', 'enable');
INSERT INTO `usr_user` VALUES ('6', 'sub', '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92', null, null, null, null, null, 'disable');
INSERT INTO `usr_user` VALUES ('7', 'contributor', '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92', null, null, null, null, null, 'disable');

-- ----------------------------
-- Table structure for usr_user_role
-- ----------------------------
DROP TABLE IF EXISTS `usr_user_role`;
CREATE TABLE `usr_user_role` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `userId` int(11) DEFAULT NULL,
  `roleId` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `userId` (`userId`),
  CONSTRAINT `userId` FOREIGN KEY (`userId`) REFERENCES `usr_user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of usr_user_role
-- ----------------------------
INSERT INTO `usr_user_role` VALUES ('1', '1', '1');
INSERT INTO `usr_user_role` VALUES ('2', '5', '3');
INSERT INTO `usr_user_role` VALUES ('3', '5', '5');
INSERT INTO `usr_user_role` VALUES ('4', '2', '4');
INSERT INTO `usr_user_role` VALUES ('5', '6', '2');

最后的测试代码如下:

package cn.zifangsky.test.shiro.func;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.ExpiredCredentialsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import junit.framework.Assert;

@RunWith(JUnit4.class)
public class RoleFuncTest {
    
    @Test
    public void test(){
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:cn/zifangsky/test/shiro/func/shiro-jdbc-func.ini");
        SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);
        
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("admin", "8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918");
        try {
            subject.login(token);
            Assert.assertEquals(true, subject.isAuthenticated());
            
            //判断用户是否拥有某个角色
            System.out.println(subject.hasRole("manager"));  //true
            System.out.println(subject.hasRole("editor"));  //false
            
            //判断是否被授权
            System.out.println(subject.isPermitted("YHGL:CX"));  //true
            System.out.println(subject.isPermitted("YHGL:XZ"));  //true
            
            subject.logout();
        } catch (IncorrectCredentialsException e) {
            System.out.println("登录密码错误. Password for account " + token.getPrincipal() + " was incorrect.");  
        } catch (ExcessiveAttemptsException e) {  
            System.out.println("登录失败次数过多");  
        } catch (LockedAccountException e) {  
            System.out.println("帐号已被锁定. The account for username " + token.getPrincipal() + " was locked.");  
        } catch (DisabledAccountException e) {  
            System.out.println("帐号已被禁用. The account for username " + token.getPrincipal() + " was disabled.");  
        } catch (ExpiredCredentialsException e) {  
            System.out.println("帐号已过期. the account for username " + token.getPrincipal() + "  was expired.");  
        } catch (UnknownAccountException e) {  
            System.out.println("帐号不存在. There is no user with username of " + token.getPrincipal());  
        } 
        
    }
}

对应的配置文件shiro-jdbc-func.ini:

[main]  
dataSource=org.springframework.jdbc.datasource.DriverManagerDataSource
dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql://127.0.0.1:3306/rbac_db
dataSource.username=root
dataSource.password=root

jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.permissionsLookupEnabled = true  
jdbcRealm.dataSource=$dataSource
#用户认证(登录)查询语句,以用户名为查询条件
jdbcRealm.authenticationQuery = SELECT password FROM usr_user WHERE username = ?
#用户角色查询语句,以用户名为查询条件,判断用户是否拥有某个角色
jdbcRealm.userRolesQuery = SELECT usr_role.roleName from usr_user,usr_user_role,usr_role WHERE usr_user.username = ? AND usr_user.id = usr_user_role.userId AND usr_user_role.roleId = usr_role.id
#资源许可查询语句,以角色名称为查询条件,判断角色是否拥有某个资源的许可
jdbcRealm.permissionsQuery = SELECT usr_func.code from usr_role,usr_role_func,usr_func WHERE usr_role.roleName = ? AND usr_role.id = usr_role_func.roleId AND usr_role_func.funcId = usr_func.id

securityManager.realms=$jdbcRealm

关于这个配置文件中定义的大部分内容都已经在上面的例子中说过了,唯一新添加的内容是:自定义了用户认证、角色查询以及权限查询的SQL语句

该测试用例最后的输出结果如下:

true
false
true
true

关于shiro框架的一些基本用法介绍就到此结束了。我将在下一篇文章中介绍如何非入侵地将shiro权限管理集成到Spring等WEB开发框架中,敬请期待!

原文地址:https://www.zifangsky.cn/770.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • 身份验证,即在应用中谁能证明他就是他本人。一般提供如他们的身份ID一些标识信息来表明他就是他本人,如提供身份证,用...
    小孩真笨阅读 503评论 0 0
  • 一.Shiro简介 Shiro框架是和spring security框架作用差不多的一个安全认证授权框架,但它更加...
    兴厚阅读 5,470评论 0 14
  • 一:基础概念 什么是权限管理 权限管理包括用户身份认证和授权两部分,简称认证授权。对于需要访问控制的资源用户首先经...
    QGUOFENG阅读 540评论 0 0
  • 弓长是你姓 桂香八月中 芬芳乃花蕊 印在吾心中 2017.10.14. 赠同学
    宋刚易海游龍阅读 133评论 0 0
  • 找一种你喜欢用到工作中的语言修复问题(公开)发布工作写博客保持健康心态的小技巧 “哦,天那。相比其他开发者,我又笨...
    极客学院Wiki阅读 1,202评论 1 6