简介:讲解自定义Realm实战基础
-
步骤:
- 创建一个类 ,继承AuthorizingRealm->AuthenticatingRealm->CachingRealm->Realm
- 重写授权方法 doGetAuthorizationInfo
- 重写认证方法 doGetAuthenticationInfo
-
方法:
- 当用户登陆的时候会调用 doGetAuthenticationInfo
- 进行权限校验的时候会调用: doGetAuthorizationInfo
-
对象介绍
-
UsernamePasswordToken : 对应就是 shiro的token中有Principal和Credential
-
UsernamePasswordToken-》HostAuthenticationToken-》AuthenticationToken
-
-
SimpleAuthorizationInfo:代表用户角色权限信息
-
SimpleAuthenticationInfo :代表该用户的认证信息
-
Apache Shiro自定义Realm实战
现在来小试牛刀一下: 思考一个登录案例,我们有一个登录界面,要检验用户名和密码,如果密码正确才能让后端返回状态码200。我们这个案例如果不使用数据库,我们可以这样使用shiro来实现。
QuickStartTest6.java
package com.lzh;
/**
* @Author:kaiyang.cui
* @Package:com.lzh
* @Project:lzh_shiro
* @name:QuickStartTest
* @Date:2023/3/27 下午2:05
* @Filename:QuickStartTest
* @Description: Apache Shiro自定义Readl实战
* @Version:1.0
*/
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.Before;
import org.junit.Test;
/**
* 自定义realm,一定会走AuthorizingRealm类中的doGetAuthenticationInfo方法,
* 我们既然要自定义realm就要自定义一个CustomRealm继承AuthorizingRealm
* 然后重写doGetAuthorizationInfo和doGetAuthenticationInfo方法
*
*/
public class QuickStartTest6 {
private CustomRealm customRealm = new CustomRealm();
private DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
@Before
public void init(){
defaultSecurityManager.setRealm(customRealm);
SecurityUtils.setSecurityManager(defaultSecurityManager);
}
@Test
public void testAuthentication() {
// 获取当前操作的主体
Subject subject = SecurityUtils.getSubject();
// 模拟用户输入的用户名和密码
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack", "123");
// 登录
subject.login(usernamePasswordToken);
// 获取验证结果 isAuthenticated() 是否授权,结果是boolen
System.out.println("认证结果:" + subject.isAuthenticated());
// 拿到主体标识属性
System.out.println("getPrincipal认证结果-实际上就是获取登录用户账号" + subject.getPrincipal());
}
}
自定义realm
CustomRealm.java
自定义realm,一定会走AuthorizingRealm类中的doGetAuthenticationInfo方法, 我们既然要自定义realm就要自定义一个CustomRealm继承AuthorizingRealm 然后重写doGetAuthorizationInfo和doGetAuthenticationInfo方法
package com.lzh;
import cn.hutool.core.util.StrUtil;
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.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import java.util.HashMap;
import java.util.Map;
/**
* @Author:kaiyang.cui
* @Package:com.lzh
* @Project:lzh_shiro
* @name:CustomRealm
* @Date:2023/3/27 下午8:36
* @Filename:CustomRealm
* @Description:Apache Shiro自定义Readl实战
* @Version:1.0
*/
public class CustomRealm extends AuthorizingRealm {
private final Map<String,String> map = new HashMap<>();
{
map.put("zhangsan", "123456");
map.put("lisi", "123456");
map.put("wangwu", "123456");
map.put("jack", "123");
}
// 进行权限校验的时候会调用
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("校验权限 doGetAuthorizationInfo");
return null;
}
//进行用户登录的时候会调用
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("认证 doGetAuthenticationInfo");
// 从token获取身份信息,token代表用户输入的信息
String name = (String) token.getPrincipal();
// 模拟从数据库中,根据用户获取密码
String pwd = getPwdByUsernameFromDB(name);
if (StrUtil.isBlank(name)) {
return null;
}
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name, pwd,this.getName());
return simpleAuthenticationInfo;
}
private String getPwdByUsernameFromDB(String name) {
return map.get(name);
}
}
Result:
认证 doGetAuthenticationInfo
认证结果:true
getPrincipal认证结果-实际上就是获取登录用户账号jack
完整版:校验登录后角色和权限信息 QuickStartTest6.java
package com.lzh;
/**
* @Author:kaiyang.cui
* @Package:com.lzh
* @Project:lzh_shiro
* @name:QuickStartTest
* @Date:2023/3/27 下午2:05
* @Filename:QuickStartTest
* @Description: Apache Shiro自定义Readl实战
* @Version:1.0
*/
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.Before;
import org.junit.Test;
/**
* 自定义realm,一定会走AuthorizingRealm类中的doGetAuthenticationInfo方法,
* 我们既然要自定义realm就要自定义一个CustomRealm继承AuthorizingRealm
* 然后重写doGetAuthorizationInfo和doGetAuthenticationInfo方法
*
*/
public class QuickStartTest6 {
private CustomRealm customRealm = new CustomRealm();
private DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
@Before
public void init(){
defaultSecurityManager.setRealm(customRealm);
SecurityUtils.setSecurityManager(defaultSecurityManager);
}
@Test
public void testAuthentication() {
// 获取当前操作的主体
Subject subject = SecurityUtils.getSubject();
// 模拟用户输入的用户名和密码
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack", "123");
// 登录
subject.login(usernamePasswordToken);
// 获取验证结果 isAuthenticated() 是否授权,结果是boolen
System.out.println("认证结果:" + subject.isAuthenticated());
// 拿到主体标识属性
System.out.println("getPrincipal认证结果-实际上就是获取登录用户账号" + subject.getPrincipal());
// 是否有对应的角色
System.out.println("是否有user角色:" + subject.hasRole("admin"));
// 是否有对应的权限
System.out.println("是否有对应的权限:" + subject.isPermitted("video:find"));
}
}
自定义realm->CustomRealm.java
package com.lzh;
import cn.hutool.core.util.StrUtil;
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.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static org.apache.shiro.web.filter.mgt.DefaultFilter.rest;
import static org.apache.shiro.web.filter.mgt.DefaultFilter.roles;
/**
* @Author:kaiyang.cui
* @Package:com.lzh
* @Project:lzh_shiro
* @name:CustomRealm
* @Date:2023/3/27 下午8:36
* @Filename:CustomRealm
* @Description:Apache Shiro自定义Realm实战
* @Version:1.0
*/
public class CustomRealm extends AuthorizingRealm {
private final Map<String,String> map = new HashMap<>();
{
map.put("zhangsan", "123456");
map.put("lisi", "123456");
map.put("wangwu", "123456");
map.put("jack", "123");
}
private final Map<String,Set<String>> persistentMap = new HashMap<>();
{
// 这里 set1 指的是普通用户权限
Set<String> set1 = new HashSet<>();
// 这里set2 指的是管理员权限
Set<String> set2 = new HashSet<>();
set1.add("video:find");
set1.add("video:buy");
set2.add("video:add");
set2.add("video:delete");
persistentMap.put("jack", set1);
persistentMap.put("lzh", set1);
}
private final Map<String,Set<String>> roleMap = new HashMap<>();
{
// 这里 set1 指的是普通用户角色
Set<String> set1 = new HashSet<>();
// 这里set2 指的是管理员角色
Set<String> set2 = new HashSet<>();
set1.add("user");
set2.add("admin");
set2.add("user");
roleMap.put("jack", set1);
roleMap.put("lzh", set1);
}
// 进行权限校验的时候会调用
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("校验权限 doGetAuthorizationInfo");
// PrincipalCollection principals 是拿到用户从后端获取的账号的信息
// 模拟从数据库中获取到用户的登录账号
String name = (String) principals.getPrimaryPrincipal();
/**
* 下面这段代码在真实到项目开发中是有问题的,因为数据表中用户是与角色挂钩的;角色是与权限挂钩的。
* 正确的流程应该是根据用户的登录名查到到角色集合,然后根据角色取查询数据表中到权限集合。
* 这里是为了简化演示流程,才直接根据登录名查询用户权限集合的!!!
*
*/
// 模拟从数据库中获取到用户的权限
Set<String> permissions = getPermissionsByNameFromDB(name);
// 模拟从数据库中获取到用的角色
Set<String> roles = getRolesByNameFromDB(name);
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.setRoles(roles);
simpleAuthorizationInfo.setStringPermissions(permissions);
return simpleAuthorizationInfo;
}
//进行用户登录的时候会调用
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("认证 doGetAuthenticationInfo");
// 从token获取身份信息,token代表用户输入的信息
String name = (String) token.getPrincipal();
// 模拟从数据库中,根据用户获取密码
String pwd = getPwdByUsernameFromDB(name);
if (StrUtil.isBlank(name)) {
return null;
}
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name, pwd,this.getName());
return simpleAuthenticationInfo;
}
private String getPwdByUsernameFromDB(String name) {
return map.get(name);
}
/**
* 模拟用户从数据库获取角色集合
* @param name
* @return
*/
private Set<String> getRolesByNameFromDB(String name) {
return roleMap.get(name);
}
/**
* 模拟用户从数据库获取权限集合
* @param name
* @return
*/
private Set<String> getPermissionsByNameFromDB(String name) {
return persistentMap.get(name);
}
}
Result
认证结果:true
getPrincipal认证结果-实际上就是获取登录用户账号jack
校验权限 doGetAuthorizationInfo
是否有user角色:false
是否有对应的权限:true
shiro是连载文章,欢迎关注我的掘金。