深入浅出Shiro框架:认证流程与基本概念详解

更新:11-07 民间故事 我要投稿 纠错 投诉

主题:即“当前操作用户”。不过,在Shiro 中,Subject 的概念不仅仅指人,还可以是第三方进程、后台账户(Daemon Accounts)或者其他类似的东西。它只是意味着“软件当前正在与之交互的内容”。但对于大多数目的和用途,您可以将其视为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

* */

@测试

公共无效测试Hello(){

//1 获取SecurityManager工厂

Factoryfactory=new IniSecurityManagerFactory("classpath:cn/zifangsky/test/shiro/base/shiro.ini");

//2 获取SecurityManager实例并将其绑定到SecurityUtils

SecurityManager securityManager=factory.getInstance();

SecurityUtils.setSecurityManager(securityManager);

//3 获取Subject并创建用户名/密码验证Token

主题subject=SecurityUtils.getSubject();

UsernamePasswordToken 令牌=new UsernamePasswordToken("admin", "admin");

尝试{

//4 登录,即:身份认证

主题.登录(令牌);

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)

公共类Helloworld {

}同时上面使用的shiro.ini配置文件如下:

[用户]

管理员=管理员

test=123456 (2) 自定义领域:

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

i) 定制的CustomRealm.java:

包cn.zifangsky.test.shiro.base;

导入org.apache.shiro.authc.AuthenticationException;

导入org.apache.shiro.authc.AuthenticationInfo;

导入org.apache.shiro.authc.AuthenticationToken;

导入org.apache.shiro.authc.In CorrectCredentialsException;

导入org.apache.shiro.authc.SimpleAuthenticationInfo;

导入org.apache.shiro.authc.UnknownAccountException;

导入org.apache.shiro.authc.UsernamePasswordToken;

导入org.apache.shiro.realm.Realm;

公共类CustomRealm 实现Realm {

/**

* 返回唯一的Realm 名称

* */

@覆盖

公共字符串getName() {

返回“自定义领域”;

}

/**

* 判断该Realm是否支持该Token

* */

@覆盖

公共布尔支持(AuthenticationToken令牌){

//仅支持UsernamePasswordToken类型的Token

返回用户名密码令牌的令牌实例;

}

/**

* 定制认证

* */

@覆盖

公共AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) 抛出AuthenticationException {

//根据token获取需要认证的信息(登录时输入的信息)

字符串用户名=(字符串) token.getPrincipal(); //获取用户名

字符串密码=String.valueOf((char[])token.getCredentials()); //获取密码

if(!"test".equals(用户名))

抛出新的UnknownAccountException();

if(!"123456".equals(密码))

抛出新的In CorrectCredentialsException();

return new SimpleAuthenticationInfo(用户名, 密码, getName());

}

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

#声明一个自定义领域

customRealm=cn.zifangsky.test.shiro.base.CustomRealm

#指定securityManager的realms实现

securityManager.realms=$customRealmiii) 测试方法:

/**

* 测试自定义Realm

* */

@测试

公共无效testCustomRealm(){

//1 获取SecurityManager工厂

Factoryfactory=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=SecurityUtils.getSubject();

UsernamePasswordToken 令牌=new UsernamePasswordToken("test", "123456");

尝试{

//4 登录,即:身份认证

主题.登录(令牌);

System.out.println("登录认证成功");

} catch (AuthenticationException e) {

//5 认证失败

System.err.println("认证失败");

}

//6 退出

subject.logout();

关于这个测试方法,除了使用不同的ini配置文件之外,其余与上面的例子相同,这里不再赘述。

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

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

i) 测试中使用的SQL语句:

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

----------------------------

-- Roles_permissions 的表结构

----------------------------

如果存在`roles_permissions`则删除表;

创建表`roles_permissions` (

`id` bigint(20) NOT NULL AUTO_INCRMENT,

`角色名称` varchar(100) 默认为NULL,

`权限` varchar(100) 默认为NULL,

主键(`id`),

唯一键`idx_roles_permissions`(`role_name`,`permission`)

) 引擎=InnoDB AUTO_INCRMENT=2 默认字符集=utf8;

----------------------------

-- 角色_权限的记录

----------------------------

插入`roles_permissions` 值("1", "admin", "/");

----------------------------

--用户表结构

----------------------------

如果存在“用户”,则删除表;

创建表“用户”(

`id` bigint(20) NOT NULL AUTO_INCRMENT,

`用户名` varchar(100) 默认为NULL,

`密码` varchar(100) 默认为NULL,

`password_salt` varchar(100) 默认为NULL,

主键(`id`),

唯一键“idx_users_username”(“用户名”)

) 引擎=InnoDB AUTO_INCRMENT=2 默认字符集=utf8;

----------------------------

-- 用户记录

----------------------------

INSERT INTO `users` VALUES ("1", "admin", "123456", null);

----------------------------

-- user_roles 的表结构

----------------------------

如果存在`user_roles`则删除表;

创建表`user_roles` (

`id` bigint(20) NOT NULL AUTO_INCRMENT,

`用户名` varchar(100) 默认为NULL,

`角色名称` varchar(100) 默认为NULL,

主键(`id`),

唯一键“idx_user_roles”(“用户名”,“角色名”)

) ENGINE=InnoDB AUTO_INCRMENT=2 默认字符集=utf8;

----------------------------

-- 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.用户名=root

数据源.密码=root

jdbcRealm.dataSource=$dataSource

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

iii) 测试方法:

/**

* 测试JDBC 领域

* */

@测试

公共无效testJdbcRealm(){

//1 获取SecurityManager工厂

Factoryfactory=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=SecurityUtils.getSubject();

UsernamePasswordToken 令牌=new UsernamePasswordToken("admin", "123456");

尝试{

//4 登录,即:身份认证

主题.登录(令牌);

System.out.println("登录认证成功");

} catch (AuthenticationException e) {

//5 认证失败

System.err.println("认证失败");

}

//6 退出

subject.logout();

}显然,运行这个方法就可以登录成功了,输出结果略有不同

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

包cn.zifangsky.test.shiro.func;

导入java.util.Arrays;

导入org.apache.shiro.SecurityUtils;

导入org.apache.shiro.authc.UsernamePasswordToken;

导入org.apache.shiro.config.IniSecurityManagerFactory;

导入org.apache.shiro.mgt.SecurityManager;

导入org.apache.shiro.subject.Subject;

导入org.apache.shiro.util.Factory;

导入org.junit.Test;

导入org.junit.runner.RunWith;

导入org.junit.runners.JUnit4;

@RunWith(JUnit4.class)

公共类角色测试{

/**

* 粒度大。如果某个角色不再存在,则需要删除该用户对应的所有角色信息。

* */

@测试

公共无效测试HasRole(){

Factoryfactory=new IniSecurityManagerFactory("classpath:cn/zifangsky/test/shiro/func/shiro-role.ini");

SecurityManager securityManager=factory.getInstance();

SecurityUtils.setSecurityManager(securityManager);

主题subject=SecurityUtils.getSubject();

UsernamePasswordToken 令牌=new UsernamePasswordToken("admin", "admin");

主题.登录(令牌);

System.out.println(subject.hasRole("role1"));

System.out.println(subject.hasAllRoles(Arrays.asList("角色1", "角色2")));

boolean[] results=subject.hasRoles(Arrays.asList("role1", "role2", "role3"));

System.out.println("结果[0]: " + 结果[0]);

System.out.println("结果[1]: " + 结果[1]);

System.out.println("结果[2]: " + 结果[2]);

//subject.checkRole("role3");

}

/**

* 小粒度,如果某个角色不再存在,只需删除该角色

* */

@测试

公共无效测试IsPermited(){

Factoryfactory=new IniSecurityManagerFactory("classpath:cn/zifangsky/test/shiro/func/shiro-permission.ini");

SecurityManager securityManager=factory.getInstance();

SecurityUtils.setSecurityManager(securityManager);

主题subject=SecurityUtils.getSubject();

UsernamePasswordToken 令牌=new UsernamePasswordToken("admin", "admin");

主题.登录(令牌);

System.out.println(subject.isPermission("user:create"));

System.out.println(subject.isPermissionAll("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(){ Factoryfactory = 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开发框架中,敬请期待!

关于深入浅出Shiro框架:认证流程与基本概念详解的内容到此结束,希望对大家有所帮助。

用户评论

站上冰箱当高冷

终于找到一篇关于Shiro的文章了,想学习一下权限控制.

    有16位网友表示赞同!

殃樾晨

这个框架在实际项目中应用比较广泛吧?

    有12位网友表示赞同!

↘▂_倥絔

Shiro认证流程挺复杂的,需要好好研究一下。

    有15位网友表示赞同!

逃避

看评论说这篇入门不错?准备来试试看。

    有13位网友表示赞同!

来自火星的我

之前用过别的权限管理框架,想体验下Shiro的感觉.

    有8位网友表示赞同!

淡写薰衣草的香

了解基本的知识点很重要呀,这篇文章应该能帮助到我。

    有6位网友表示赞同!

孤者何惧

学习技术新东西总是不太容易,希望这篇文章能够说得通俗易懂

    有18位网友表示赞同!

夜晟洛

Shiro的认证流程是什么样的呢?可以分享一下吗?

    有18位网友表示赞同!

追忆思域。

权限控制对于Web项目非常重要,必须要学习下 Shiro.

    有5位网友表示赞同!

゛指尖的阳光丶

希望能通过这篇文章了解到Shiro的使用方法。

    有6位网友表示赞同!

鹿先森,教魔方

我刚开始学Javaweb, 看起来这个框架挺有意思的!

    有9位网友表示赞同!

ˉ夨落旳尐孩。

之前想学习 Shiro 认证流程,但一直找不到合适的资料,这篇文章正好解决了我这个问题!

    有11位网友表示赞同!

放肆丶小侽人

好文推荐!感谢分享.

    有19位网友表示赞同!

微信名字

Shiro入门难吗?请问学习这方面的资源有哪些推荐.

    有8位网友表示赞同!

为爱放弃

希望能够深入了解 Shiro 的概念和原理,这篇入门讲解不错!

    有13位网友表示赞同!

莫飞霜

学习效果怎么样呢?会不会觉得太基础了。

    有18位网友表示赞同!

怀念·最初

感觉这个框架的名称很熟悉?之前见过吗?

    有9位网友表示赞同!

鹿叹

对于初学者来说,这篇文章会不会过于专业?

    有5位网友表示赞同!

信仰

Shiro 可以用来做什么样的项目开发呢?

    有16位网友表示赞同!

伤离别

希望能有更多关于 Shiro 的学习资源,比如视频教程等.

    有14位网友表示赞同!

【深入浅出Shiro框架:认证流程与基本概念详解】相关文章:

1.蛤蟆讨媳妇【哈尼族民间故事】

2.米颠拜石

3.王羲之临池学书

4.清代敢于创新的“浓墨宰相”——刘墉

5.“巧取豪夺”的由来--米芾逸事

6.荒唐洁癖 惜砚如身(米芾逸事)

7.拜石为兄--米芾逸事

8.郑板桥轶事十则

9.王献之被公主抢亲后的悲惨人生

10.史上真实张三丰:在棺材中竟神奇复活

上一篇:2024年破墓百度网盘资源获取方法及观看教程汇总 下一篇:揭秘高铁夜间限行之谜:为何只能在白天运行?