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即文件系统中,通过给定的格式,从文件中查找相应的数据是否存在。

步骤:

  1. 删除之前SimpleAccountRealm,在实体中创建IniRealm并实例化。在构造方法中传入相应的user.ini地址。此文件地址一般写为:classpath:user.ini的形式。需要在相应的包中建立resource文件夹,并且放入user.ini文件。
  2. user.ini文件的定义格式为:[users] 用户名=密码,角色 [roles] 角色=权限名(例子:amdin=user:delete,user:update)
  3. 与之前认证与授权步骤一样,直接将IniRealm放入到SecurityManager中,进行登录认证,之后进行checkRoles验证与checkPersimmon验证权限等操作即可。
  4. 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的方式访问数据库,通过与数据库的连接,验证相应的登录用户与授权。

  1. jdbcRealm新建其实例,并初始化。
  2. Maven中引入mysql的驱动以及相应数据源的类。
  3. 新建数据源作为成员变量,并且在静态快中初始化url、username、password等。
  4. 将数据源设置到到jdbcrealm中,并且将此realm设置到权限管理中。
  5. 之后进行登录等验证,jdbcrealm会在源码的地方写入了默认的进行认证与授权的sql语句,以及表名什么的都规定好了。如果想更改,则写入新的sql语句,并且调用jdbcrealm中的设置认证Query、设置权限Query、设置角色查询的方法,进行修改。
  6. 当查询权限的时候,会报错,即便库汇总有次权限,仍旧会报错,因为你需要在jdbcrealm中开启persimisson的为true即可:setPermissionsLookupEnabled(true)。(默认为false)
  7. 其他的与之前的认证与授权的步骤一致。

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 {    Map
userMap = 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 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Shiro - Spring + Jedis(会话、缓存、自动登录)整合篇
下一篇:浙大版《C语言程序设计(第3版)》题目集 - 习题11-8 单链表结点删除(20 分)

发表评论

最新留言

能坚持,总会有不一样的收获!
[***.219.124.196]2024年04月30日 06时45分57秒