Shiro【自定义Realm实战】

摘要:
因此,您需要自定义Realm才能使用它。2、创建继承AuthorizationRealm的类的步骤会重写身份验证方法doGetAuthenticationInfo会重写授权方法doGetAuthorizationInfo。在该方法中,对应的对象SimpleAuthenticationInfo:表示用户的身份验证信息SimpleAuthorizationInfo:表示该用户的角色权限信息。3.代码实现说明:在这种情况下,不会从数据库中查询任何真实数据,因此使用集合模拟的数据。

一、前言

虽然 Shiro 给我们提供了很多内置的 Realm,但在企业开发中,这往往不适用于项目中。

所以,都需要自定义 Realm 来使用。

二、步骤

  1. 创建一个类 ,继承 AuthorizingRealm

​ (继承关系:自定义Realm->AuthorizingRealm->AuthenticatingRealm->CachingRealm->Realm)

  1. 重写认证方法 doGetAuthenticationInfo

​ 重写授权方法 doGetAuthorizationInfo

  1. 在方法中分别返回对应的对象

​ SimpleAuthenticationInfo :代表该用户的认证信息
​ SimpleAuthorizationInfo:代表用户角色权限信息

三、代码实现

注:

本文的案例中没有从数据库中查询真实的数据,所以使用集合模拟的数据。

在实际开发中,只需要 service 层写好的方法从数据库查询数据即可。

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;

/**
 * 自定义的 Redlm 步骤:
 * 1.继承AuthorizingRealm
 * 2.重写授权方法 doGetAuthorizationInfo
 *   重写认证方法 doGetAuthenticationInfo
 * 3.在方法中分别返回对应的对象
 *   SimpleAuthorizationInfo:代表用户角色权限信息
     SimpleAuthenticationInfo :代表该用户的认证信息
 */
public class CustomRealm extends AuthorizingRealm {

    private final Map<String,String> userInfoMap = new HashMap<>();
    {
        userInfoMap.put("jack","123");
        userInfoMap.put("xdclass","456");
    }

    //user -> role
    private final Map<String,Set<String>> roleMap = new HashMap<>();
    {
        Set<String> set1 = new HashSet<>();
        Set<String> set2 = new HashSet<>();

        set1.add("role1");
        set1.add("role2");

        set2.add("root");

        roleMap.put("jack",set1);
        roleMap.put("xdclass",set2);
    }

    //role -> permission
    private final Map<String,Set<String>> permissionMap = new HashMap<>();
    {
        Set<String> set1 = new HashSet<>();
        Set<String> set2 = new HashSet<>();

        set1.add("video:find");
        set1.add("video:buy");

        set2.add("video:add");
        set2.add("video:delete");

        permissionMap.put("jack",set1);
        permissionMap.put("xdclass",set2);
    }

    /**
     * 执行认证操作时,SecurityManager 会执行此方法
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // UsernamePasswordToken -> HostAuthenticationToken -> AuthenticationToken
        // 在实际开发的时候,authenticationToken是需要前端传递过来的用户输入的账号和密码

        // 获取用户唯一标识(俗称“账号”)
        String name = (String)authenticationToken.getPrincipal();
        // 根据账号从数据库中获取密码
        String pwd = getPwdByUserNameFromDB(name);
        if( pwd == null || "".equals(pwd)){
            return null;
        }
        // 将账号和密码封装到 SimpleAuthenticationInfo 对象中进行返回
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name, pwd, this.getName());

        return simpleAuthenticationInfo;
    }

    /**
     * 执行授权操作时,SecurityManager 会执行此方法
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // 获取“账号”
        String name = (String)principals.getPrimaryPrincipal();

        // 模拟从数据库中获取角色
        Set<String> roles = getRolesByNameFromDB(name);

        // 模拟从数据库中获取权限
        //(另外,此处本来是应该的根据角色获取权限的,但因为本来也只是模拟,所以为了简便,则直接根据账号获取的权限)
        Set<String> permissions = getPermissionsByNameFromDB(name);

        // 将角色和权限等信息封装到 SimpleAuthorizationInfo 进行返回
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.setRoles(roles);
        simpleAuthorizationInfo.setStringPermissions(permissions);

        return simpleAuthorizationInfo;
    }

    /**
     * 模拟从数据库中获取密码
     * @param name
     * @return
     */
    private String getPwdByUserNameFromDB(String name) {
        return userInfoMap.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 permissionMap.get(name);
    }

}

测试代码如下:

/**
 * 测试自定义的Realm
 */
public class CustomRealmTest {

    private CustomRealm customRealm = new CustomRealm();
    private DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();

    @Before
    public void init(){
        //构建环境
        defaultSecurityManager.setRealm(customRealm);
        SecurityUtils.setSecurityManager(defaultSecurityManager);
    }

    @Test
    public void testAuthentication() {
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack", "123");

        Subject subject = SecurityUtils.getSubject();
        subject.login(usernamePasswordToken);

        System.out.println(" 认证结果:"+subject.isAuthenticated());
        System.out.println(" getPrincipal=" + subject.getPrincipal());
        System.out.println("是否有对应的角色:"+subject.hasRole("role1"));
        System.out.println("是否有对应的权限:"+subject.isPermitted("video:add"));
    }
}

四、代码解析

(一)方法

当用户登陆的时候会调用 doGetAuthenticationInfo

进行权限校验的时候会调用: doGetAuthorizationInfo

(二)代码中的类(对象)
  1. UsernamePasswordToken :用来封装用户(Subject)传递过来的账号和密码

​ (继承体系:UsernamePasswordToken -> HostAuthenticationToken -> AuthenticationToken)

  1. SimpleAuthenticationInfo :用来封装用户的认证信息

  2. SimpleAuthorizationInfo:用来封装用户的角色权限信息

五、认证和授权流程源码分析

在编辑器中通过 Debug 方式则能分析出认证和授权的大致流程如下:

(一)认证
认证流程解读:
    subject.login(usernamePasswordToken);
    DelegatingSubject->login()
    DefaultSecurityManager->login()
    AuthenticatingSecurityManager->authenticate()
    AbstractAuthenticator->authenticate()
    ModularRealmAuthenticator->doAuthenticate()
    ModularRealmAuthenticator->doSingleRealmAuthentication()
    AuthenticatingRealm->getAuthenticationInfo()
(二)授权
授权流程解读(查询角色):
    subject.checkRole("admin")
    DelegatingSubject->checkRole()
    AuthorizingSecurityManager->checkRole()
    ModularRealmAuthorizer->checkRole()
    AuthorizingRealm->hasRole()
    AuthorizingRealm->doGetAuthorizationInfo()
授权流程解读(查询权限):
subject.isPermitted("具体权限")
	DelegatingSubject->isPermitted()
	AuthorizingSecurityManager->isPermitted()
	ModularRealmAuthorizer->isPermitted()
	AuthorizingRealm->isPermitted()
	AuthorizingRealm->getAuthorizationInfo()
	CustomRealm->doGetAuthorizationInfo

六、总结

Realm 就是用来从数据库中获取用户的角色、权限等数据的,不要被这个名字给吓唬到。

Java新手,若有错误,欢迎指正!

免责声明:文章转载自《Shiro【自定义Realm实战】》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇安卓中多线程间通信方式设置root密码,su与sudo的区别下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

ReactNative: 了解相机第三方库react-native-camera的使用

一、简介 在前一篇文章中,初步介绍了RN提供的关于相机功能CameraRoll的使用了。很多时候,这种最基础的API有时很难满足功能需求,此时,如果不想重复造轮子,我们可以选择一个完善好用的第三库。react-native-camera就是一个非常不错的关于相机功能的第三方库,使用这个框架基本能满足大多数的需求,现在来简单研究一下。 二、安装 1、同样地道...

使用curses管理基于文本的屏幕--(八)

CD管理程序现在我们已经了解了curses所提供了功能,我们可以继续开发我们的例子程序。在这里所展示是一个使用curses库的C语言版本。他提供了一些高级的特性,包括更为清晰的屏幕信息显示以及用于跟踪列表的滚动窗口。完整的程序共页长,所以我们将其分为几部分,在每一部分中介绍一些函数。试验--一个新的CD管理程序1 首先,我们包含所有的头文件以及一些全局常量...

Java 设计模式--策略模式,枚举+工厂方法实现

项目中的一个页面跳转功能存在10个以上的if else判断,想要做一下整改 一、什么是策略模式 策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理,最终可以实现解决多重If判断问题。 1.环境(Context)角色:持有一个Strategy的引用。 2.抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象...

ant Form 常用 api

经过 Form.create 包装的组件将会自带 this.props.form 属性,this.props.form 提供的 API 如下: 注意:使用 getFieldsValue getFieldValue setFieldsValue 等时,应确保对应的 field 已经用 getFieldDecorator 注册过了。 方法      说明...

Delphi使用TStringHash实现建立类(有点像反射)

1 unit Unit1; 2 3 interface 4 5 uses 6 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 7 Dialogs, StdCtrls, jpeg, ExtCtrls,...

Android 解析后台返回为Json数据的简单例子

大家好,今天给大家分享下Android解析Json的例子,我这里自己安装了Tomcat,让自己电脑充当下服务器,最重要的是,返回结果自己可以随便修改。 首先看下Json的定义,以及它和XML的比较: JSON的定义: 一种轻量级的数据交换格式,具有良好的可读和便于快速编写的特性。业内主流技术为其提供了完整的解决方案(有点类似于正则表达式 ,获得了当今大部分...