Shiro - 基础篇
发布日期:2021-06-30 23:50:38
浏览次数:2
分类:技术文章
本文共 10322 字,大约阅读时间需要 34 分钟。
由于权限管理模块一般都是在资源一层,如果更深一层的话,则可能会与业务代码进行耦合,故提倡Shiro做权限管理,Spring官网也是用Shiro进行的权限管理。
- SUB 主体
- Authenticator 认证器(登陆)
- Authorizer 授权器(访问权限)
- SessionManager Shiro自己的Session不依赖于Web
- SessionDAO Session操作增删改查
- CacheManager 缓存操作(缓存角色和权限)
- Reaims Shiro和数据库直接的一个桥梁
AuthenticationTest.java
package com.cheng.test;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.mgt.DefaultSecurityManager;import org.apache.shiro.realm.SimpleAccountRealm;import org.apache.shiro.subject.Subject;import org.junit.Before;import org.junit.Test;public class AuthenticationTest { SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm(); @Before public void addUser() { simpleAccountRealm.addAccount("cheng", "123", "admin", "user"); } @Test public void testAuthentication() { // 1. 构建 SecurityManager 环境 DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); defaultSecurityManager.setRealm(simpleAccountRealm); // 2. 主体提交认证请求 SecurityUtils.setSecurityManager(defaultSecurityManager); Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("cheng", "123"); subject.login(token); System.out.println("isAuthenticated: " + subject.isAuthenticated()); // 检查用户是否有 admin 角色 subject.checkRoles("admin", "user"); // 退出认证 subject.logout(); System.out.println("isAuthenticated: " + subject.isAuthenticated()); }}
IniRealm
Shiro的IniRealm 形式:此形式主要是将数据存放到相应的user.ini即文件系统中,通过给定的格式,从文件中查找相应的数据是否存在。
步骤:
- 删除之前SimpleAccountRealm,在实体中创建IniRealm并实例化。在构造方法中传入相应的user.ini地址。此文件地址一般写为:classpath:user.ini的形式。需要在相应的包中建立resource文件夹,并且放入user.ini文件。
- user.ini文件的定义格式为:[users] 用户名=密码,角色 [roles] 角色=权限名(例子:amdin=user:delete,user:update)
- 与之前认证与授权步骤一样,直接将IniRealm放入到SecurityManager中,进行登录认证,之后进行checkRoles验证与checkPersimmon验证权限等操作即可。
- Ps:中括号表示:要同时具备里面的角色才行,是 && 的关系。
user.ini
[users]cheng = 123,admin[roles]admin = user:delete,user:update
IniRealmTest.java
package com.cheng.test;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.mgt.DefaultSecurityManager;import org.apache.shiro.realm.text.IniRealm;import org.apache.shiro.subject.Subject;import org.junit.Test;public class IniRealmTest { IniRealm iniRealm = new IniRealm("classpath:user.ini"); @Test public void testAuthentication() { // 1. 构建 SecurityManager 环境 DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); defaultSecurityManager.setRealm(iniRealm); // 2. 主体提交认证请求 SecurityUtils.setSecurityManager(defaultSecurityManager); Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("cheng", "123"); subject.login(token); System.out.println("isAuthenticated: " + subject.isAuthenticated()); subject.checkRole("admin"); subject.checkPermission("user:delete"); subject.checkPermission("user:update"); }}
JdbcRealm
JdbcRealm的方式访问数据库,通过与数据库的连接,验证相应的登录用户与授权。
- jdbcRealm新建其实例,并初始化。
- Maven中引入mysql的驱动以及相应数据源的类。
- 新建数据源作为成员变量,并且在静态快中初始化url、username、password等。
- 将数据源设置到到jdbcrealm中,并且将此realm设置到权限管理中。
- 之后进行登录等验证,jdbcrealm会在源码的地方写入了默认的进行认证与授权的sql语句,以及表名什么的都规定好了。如果想更改,则写入新的sql语句,并且调用jdbcrealm中的设置认证Query、设置权限Query、设置角色查询的方法,进行修改。
- 当查询权限的时候,会报错,即便库汇总有次权限,仍旧会报错,因为你需要在jdbcrealm中开启persimisson的为true即可:setPermissionsLookupEnabled(true)。(默认为false)
- 其他的与之前的认证与授权的步骤一致。
JdbcRealm 有默认的查询语句图
pom.xml
shiro-learn com.cheng 1.0-SNAPSHOT 4.0.0 shiro-test org.apache.shiro shiro-core 1.4.0 mysql mysql-connector-java 5.1.46 com.alibaba druid 1.1.6 junit junit 4.12
JdbcRealmTest.java
package com.cheng.test;import com.alibaba.druid.pool.DruidDataSource;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.mgt.DefaultSecurityManager;import org.apache.shiro.realm.jdbc.JdbcRealm;import org.apache.shiro.subject.Subject;import org.junit.Test;public class JdbcRealmTest { DruidDataSource dataSource = new DruidDataSource(); { dataSource.setUrl("jdbc:mysql://localhost:3306/test"); dataSource.setUsername("root"); dataSource.setPassword("zy159357"); } @Test public void testAuthentication() { JdbcRealm jdbcRealm = new JdbcRealm(); jdbcRealm.setDataSource(dataSource); // 查询权限数据,默认为 false jdbcRealm.setPermissionsLookupEnabled(true); String sql = "select password from test_user where user_name = ?"; jdbcRealm.setAuthenticationQuery(sql); String roleSql = "select role_name from test_user_role where user_name = ?"; jdbcRealm.setUserRolesQuery(roleSql); String permissionSql = "select permission_name from test_user_permission where role_name = ?"; jdbcRealm.setPermissionsQuery(permissionSql); // 1. 构建 SecurityManager 环境 DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); defaultSecurityManager.setRealm(jdbcRealm); // 2. 主体提交认证请求 SecurityUtils.setSecurityManager(defaultSecurityManager); Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("cheng", "123"); subject.login(token); System.out.println("isAuthenticated: " + subject.isAuthenticated()); subject.checkRole("admin"); subject.checkRoles("admin", "user"); subject.checkPermission("user:select"); }}
自定义Realm + 安全加密
CustomRealm.java
package com.cheng.shiro.realm;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.SimpleAuthenticationInfo;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.crypto.hash.Md5Hash;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import org.apache.shiro.util.ByteSource;import java.util.HashMap;import java.util.HashSet;import java.util.Map;import java.util.Set;/** * 自定义 Realm */public class CustomRealm extends AuthorizingRealm { MapuserMap = new HashMap<>(16); { userMap.put("cheng", "66f469382db2328c876b700deb336220"); super.setName("customRealm"); } @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String username = (String) principals.getPrimaryPrincipal(); Set roles = getRolesByUserName(username); Set permissions = getPermissionsByUsername(username); SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); simpleAuthorizationInfo.setRoles(roles); simpleAuthorizationInfo.setStringPermissions(permissions); return simpleAuthorizationInfo; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { // 1. 从主体传过来的认证信息中,获得用户名 String username = (String) authenticationToken.getPrincipal(); // 2. 通过用户名到数据库中获取凭证 String password = getPasswordByUsername(username); if (password == null) { return null; } SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username, password, "customRealm"); // 设置加密的 盐 authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("cheng")); return authenticationInfo; } private Set getRolesByUserName(String username) { Set set = new HashSet<>(); // 从数据库或者缓存中获取角色数据 set.add("admin"); set.add("user"); return set; } private Set getPermissionsByUsername(String username) { Set set = new HashSet<>(); set.add("user:delete"); set.add("user:update"); return set; } /** * 模拟数据库查询凭证 */ private String getPasswordByUsername(String username) { return userMap.get(username); } public static void main(String[] args) { // 密码 + 盐 加密后的结果 Md5Hash md5Hash = new Md5Hash("123", "cheng"); System.out.println(md5Hash.toString()); }}
CustomerRealmTest.java
package com.cheng.test;import com.cheng.shiro.realm.CustomRealm;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.authc.credential.HashedCredentialsMatcher;import org.apache.shiro.mgt.DefaultSecurityManager;import org.apache.shiro.subject.Subject;import org.junit.Test;/** * 自定义 Realm */public class CustomerRealmTest { @Test public void testAuthentication() { CustomRealm customRealm = new CustomRealm(); // 1. 构建 SecurityManager 环境 DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); defaultSecurityManager.setRealm(customRealm); // 加密 HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(); // 加密算法名称 matcher.setHashAlgorithmName("md5"); // 加密次数 matcher.setHashIterations(1); // 自定义 Realm 中设置加密对象 customRealm.setCredentialsMatcher(matcher); // 2. 主体提交认证请求 SecurityUtils.setSecurityManager(defaultSecurityManager); Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("cheng", "123"); subject.login(token); System.out.println("isAuthenticated: " + subject.isAuthenticated()); subject.checkRole("admin"); subject.checkPermission("user:delete"); subject.checkPermission("user:update"); }}
下载地址:
更多教程:
转载地址:https://lux-sun.blog.csdn.net/article/details/85688151 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
能坚持,总会有不一样的收获!
[***.219.124.196]2024年04月30日 06时45分57秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
Linux运维-搭建高可用Redis缓存
2019-04-30
膜拜!阿里内部都在强推的K8S(kubernetes)学习指南,不能再详细了
2019-04-30
Linux 常用命令
2019-04-30
Android之Handler机制篇
2019-04-30
Android之网络协议篇
2019-04-30
Android之RecyclerView篇
2019-04-30
Android之Retrofit基本用法篇
2019-04-30
Netty与网络协议资料整理
2019-04-30
Golang相关资源整理
2019-04-30
设置Golang的开发环境
2019-04-30
对HTTP/2的部分理解
2019-04-30
Golang 逃逸分析
2019-04-30
golang实现大数据量文件的排序
2019-04-30
golang中的time包
2019-04-30
golang fmt包中的占位符
2019-04-30
Docker下使用Redis
2019-04-30
Redis的主从和集群设置
2019-04-30
对Redis Cluster的理解
2019-04-30
清华师哥丢了个在Github下载量50万+的项目给我,让(附源码下载地址)
2019-04-30