Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用

1 Realm简介

1.1 Realm作用

shiro最终是通过Realm获取安全数据的(如用户、角色、权限),也就是说认证或者授权都会通过Realm进行数据操作

1.2 Realm接口

1.2.1 源代码

Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用

1.2.2 方法说明

》getName:返回一个唯一的 Realm 名字

》supports:判断此 Realm 是否支持此 Token

》getAuthenticationInfo:根据 Token 获取认证信息,该方法就是用来实现认证逻辑的(从Realm的实现类org.apache.shiro.realm.AuthenticatingRealm#getAuthenticationInfo中可以看出)

1.3 AuthenticationToken

》层级关系

Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用

》关系图

Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用

》开发时一般将用户名和密码封装成一个UsernamePasswordToken对象

1.4 注意

》supports需要对Token类型进行判断,判断实参类型是否满足条件;这里指定的是AuthenticationToken类型(任何Token类型都可以传入,因为AuthenticationToken是一个父接口),所以在实现类中只需要判断实参是否是指定的Token类型即可(实际开发时传入的实参一般都是UsernamePasswordToken类型,所以在supports方法中只需要判定实参是否是这个类型即可)。

》实现认证的逻辑就是写在org.apache.shiro.realm.Realm#getAuthenticationInfo这个方法中的(从Realm的实现类org.apache.shiro.realm.AuthenticatingRealm#getAuthenticationInfo中可以看出)

1.5 简易自定义Realm

1.5.1 思路

》实现Realm接口

》getName返回一个唯一的Realm名称即可

》supports中判定实参类型是否是UsernamePasswordToken类型

》getAuthenticationInfo中实现认证逻辑

1.5.2 代码实现

Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用

package com.xunyji.demo03.shirotest.realm;
import org.apache.shiro.authc.*;
import org.apache.shiro.realm.Realm;
/**
 * @author AltEnter
 * @create 2019-01-20 20:11
 * @desc 自定义简易Realm
 **/
public class MySimpleRealm implements Realm {
 public String getName() {
 return "mySimpleRealm";
 }
 public boolean supports(AuthenticationToken token) {
 if (token instanceof UsernamePasswordToken) {
 return true;
 }
 return false;
 }
 public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
 String username = (String) token.getPrincipal();
 String password = new String((char[])token.getCredentials());
 System.out.println(String.format("用户名为:%s, 用户密码为:%s", username, password));
 if (!"fury".equals(username)) {
 System.out.println("用户名错误");
 return null;
 }
 if (!"111111".equals(password)) {
 System.out.println("密码错误");
 return null;
 }
 return new SimpleAuthenticationInfo(username, password, getName());
 }
}

Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用

1.5.3 单元测试类

Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用

package com.xunyji.demo03.shirotest.realm;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Test;
import static org.junit.Assert.*;
public class MySimpleRealmTest {
 
 @Test
 public void test01() {
 MySimpleRealm mySimpleRealm = new MySimpleRealm();
 DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
 defaultSecurityManager.setRealm(mySimpleRealm);
 SecurityUtils.setSecurityManager(defaultSecurityManager);
 Subject subject = SecurityUtils.getSubject();
 UsernamePasswordToken token = new UsernamePasswordToken("fury", "111111");
 subject.login(token);
 System.out.println(String.format("认证结果:%s", subject.isAuthenticated()));
 }
}

Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用

2 Realm源码分析

Realm接口主要是认证的主接口,但是它的一些实现类既可以进行认证也可以进行授权逻辑

2.1 Realm相关类层次图

todo: 贴图

2.2 Realm相关类说明

》CachingRealm:带有缓存实现的Realm,相当于Realm的扩展

》AuthenticatingRealm:专门做认证的Realm,它继承自CachingRealm

》AuthorizingRealm:专门做授权的Realm,因为它集成自AuthenticatingRealm,所以它也可以实现认证逻辑;自定义的Realm一般都是继承该类,然后重写里面的认证方法和授权方法即可。

》IniRealm:用ini文件存储用户信息时使用,[users]部分指定用户名/密码及其角色; [roles]部分指 定角色即权限信息;

》PropertiesRealm:用properties文件存储用户信息时使用,user.username=password,role1,role2 指定用户 名/密码及其角色;role.role1=permission1,permission2 指定角色及权限信息;

》JdbcRealm:用数据库存储用户信息时使用,通过 sql 查询相应的信息,如“select password from users where username = ?”获取用户密码,“select password, password_salt from users where username = ?”获取用户密码及盐;“select role_name from user_roles where username = ?” 获取用户角色;“select permission from roles_permissions where role_name = ?”获取角色对 应的权限信息;也可以调用相应的 api 进行自定义 sql;

2.3 AuthenticatingRealm详解

》getAuthenticationInfo:该方法是Realm中getAuthenticationInfo的实现,该方法是实现认证逻辑的;该方法是一个final方法,所以AuthenticatingRealm的子类不能重写该方法;

》doGetAuthenticationInfo:getAuthenticationInfo方法调用doGetAuthenticationInfo实现认证逻辑,该方法是一个protected方法,专门暴露给子类进行重写的,而且是子类实现认证逻辑必须重写的方法。

2.4 Realm主要实现类

2.4.1 IniRealm

》用户相关信息存储在一个ini文件中

2.4.2 PropertiesRealm

》用户相关信息存储在一个properties文件中

2.4.3 JdbcRealm

》用户信息存储在数据库中

2.5 IniRealm使用教程

2.5.1 继承关系图

Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用

2.5.2 创建一个maven工程并引入shiro、junit相关依赖

Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用

<dependency>
 <groupId>org.apache.shiro</groupId>
 <artifactId>shiro-core</artifactId>
 <version>1.4.0</version>
 </dependency>
 <dependency>
 <groupId>junit</groupId>
 <artifactId>junit</artifactId>
 <version>4.12</version>
 </dependency>

Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用

2.5.3 在resources目录下创建ini文件用于存放用户信息

》项目目录结构

Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用

》ini配置文件详解

https://blog.csdn.net/u011781521/article/details/74892074

》ini文件内容

Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用

[users]
fury=111111,role1,role2
zeus=222222,role1
[roles]
role1=user:delete,user:update,user:create,user:read
role2=car:create

Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用

》测试代码

Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用

package com.xunyji.demo03.shirotest.realm;
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;
import java.util.ArrayList;
import java.util.Arrays;
/**
 * @author AltEnter
 * @create 2019-01-17 22:07
 * @desc IniRealm测试类
 **/
public class IniRealmDemo {
 @Test
 public void iniRealmTest() {
 // 01 创建Realm
 IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
// 02 创建SecurityManager并将Realm设置到SecurityManager中
 DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
 defaultSecurityManager.setRealm(iniRealm);
// 03 将SecurityManager设置到SecurityUtils中
 SecurityUtils.setSecurityManager(defaultSecurityManager);
// 04 从SecurityUtils中获取Subject
 Subject subject = SecurityUtils.getSubject();
// 05 将用户名和用户密码封装成一个Token
 UsernamePasswordToken token = new UsernamePasswordToken("zeus", "222222");
// 06 通过Subject进行登录认证
 try {
 subject.login(token);
 } catch (Exception e) {
 e.printStackTrace();
 }
// 07 通过Subject判断登录认证结果
 System.out.println(String.format("认证结果为:%s", subject.isAuthenticated()));
 ArrayList<String> roleList = new ArrayList<String>();
 roleList.add("role1");
 System.out.println("是否有role1角色:" + Arrays.toString(subject.hasRoles(roleList)));
 System.out.println("是否有role1角色:" + subject.hasRole("role1"));
 subject.checkPermission("user:create");
 }
}

Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用

2.6 PropertiesRealm使用教程

参见2.5 + 百度

2.7 JdbcRealm使用教程

》继承关系图

Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用

》引入shiro、junit、mysql、druid依赖

Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用

<dependency>
 <groupId>org.apache.shiro</groupId>
 <artifactId>shiro-core</artifactId>
 <version>1.4.0</version>
 </dependency>
 <dependency>
 <groupId>junit</groupId>
 <artifactId>junit</artifactId>
 <version>4.12</version>
 </dependency>
 <dependency>
 <groupId>mysql</groupId>
 <artifactId>mysql-connector-java</artifactId>
 <version>5.1.45</version>
 </dependency>
 <dependency>
 <groupId>com.alibaba</groupId>
 <artifactId>druid</artifactId>
 <version>1.1.6</version>
 </dependency>

Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用

》根据JdbcRealm源码创建相关表的SQL

Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用

View Code

》测试类

Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用

package com.xunyji.demo03.shirotest.realm;
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;
/**
 * @author AltEnter
 * @create 2019-01-20 21:07
 * @desc JdbcRealm使用Demo
 **/
public class JdbcRealmDemo {
 DruidDataSource data =new DruidDataSource();
 {
 data.setUrl("jdbc:mysql://localhost:3306/shiro?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC");
 data.setUsername("root");
 data.setPassword("182838");
 }
 @Test
 public void testAuthentication(){
 JdbcRealm jdbcRealm = new JdbcRealm();
 jdbcRealm.setDataSource(data);
 jdbcRealm.setPermissionsLookupEnabled(true); // 开启权限查询功能
 String sql="select password from users where username= ?";
 jdbcRealm.setAuthenticationQuery(sql);
 String roleSql ="select role_name from user_roles where username = ?";
 jdbcRealm.setUserRolesQuery(roleSql);
 //1.构建securtymanager
 DefaultSecurityManager manager = new DefaultSecurityManager();
 manager.setRealm(jdbcRealm);
 //2.主体提交认证请求
 SecurityUtils.setSecurityManager(manager);
 Subject subject = SecurityUtils.getSubject();
 // UsernamePasswordToken token =new UsernamePasswordToken("Mark","123456");
 UsernamePasswordToken token =new UsernamePasswordToken("fury","111111");
 subject.login(token);
 //是否认证的一个方法
 boolean authenticated = subject.isAuthenticated();
 System.out.println("authenticated==============="+authenticated);
 subject.checkRole("user");
 subject.checkRole("admin");
 subject.checkPermission("user:update");
 }
}

Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用

2.8 SimpleAccountRealm使用教程

》层次关系图

Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用

》说明

这种类型是通过硬编码来存储用户数据的

》测试代码

Shrio02 Realm作用、自定义简洁Realm、Realm实现类使用

package com.xunyji.demo03.shirotest.realm;
import com.sun.org.apache.bcel.internal.generic.NEW;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
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;
/**
 * @author AltEnter
 * @create 2019-01-20 21:15
 * @desc SimpleAccountRealm使用Demo类
 **/
public class SimpleAccountRealmDemo {
 private SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();
 @Before
 public void addUser() {
 simpleAccountRealm.addAccount("fury", "111111");
 }
 @Test
 public void test01() {
 DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
 defaultSecurityManager.setRealm(simpleAccountRealm);
 SecurityUtils.setSecurityManager(defaultSecurityManager);
 Subject subject = SecurityUtils.getSubject();
 UsernamePasswordToken token = new UsernamePasswordToken("fury", "111111");
 subject.login(token);
 System.out.println(String.format("认证结果为:%s", subject.isAuthenticated()));
 subject.logout();
 System.out.println(String.format("认证结果为:%s", subject.isAuthenticated()));
 }
}

作者:寻渝记

原文:https://www.cnblogs.com/NeverCtrl-C/p/10296238.html

相关推荐