shiro之自定义Realm之继承AuthorizingRealm(*)

一.Realm基本架构
为了快速上手,我们需要知道的是,Shiro将数据库中的数据,存放到Realm这种对象中。而Shiro提供的Realm体系较为复杂,一般我们为了使用Shiro的基本目的就是:认证、授权。
在这里插入图片描述
所以,一般在真实的项目中,我们不会直接实现Realm接口,也不会直接继承最底层的功能贼复杂的IniRealm。我们一般的情况就是直接继承AuthorizingRealm,能够继承到认证与授权功能。它需要强制重写两个方法:

public class DefaultRealm extends AuthorizingRealm {
 
    //强制重新授权方法,以后再说
    protected AuthorizationInfo doGetAuthorizationInfo(
                           PrincipalCollection principalCollection) {
        return null;
    }
 
    //强制重写的认证方法
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) 
throws AuthenticationException {
        return null;
    }
}

既然说Realm将数据库中的数据存放到realm中,那么数据库操作在哪里呢?当然就是在我们的doGetAuthenticationInfo方法中操作了。有JAVAWEB经验的朋友肯定知道,用户数据一般都会放到数据库中。所以,我们在doGetAuthenticationInfo方法内部是需要查询数据库操作的。下面是一个简单重写此方法的例子。

/**
  * 强制重写的认证方法
  */
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) 
                                                          throws AuthenticationException {
        //还记得吗,token封装了客户端的帐号密码,由Subject拉客并最终带到此处
        String clientUsername = (String) token.getPrincipal();  
        //模拟一个Service
        SecurityService securityService = new SecurityService();
        //通过Service查询数据库,获取到正确的密码
        String passwordFromDB = securityService.findPasswordByUsername(clientUsername);
        if(passwordFromDB == null){
            //如果根据用户输入的用户名,去数据库中没有查询到相关的密码
            throw new UnknownAccountException();
        }
        
        /**
         * 返回一个从数据库中查出来的的凭证。用户名为clientUsername,密码为passwordFromDB 。封装成当前返回值
         * 接下来shiro框架做的事情就很简单了。
         * 它会拿你的输入的token与当前返回的这个数据库凭证SimpleAuthenticationInfo对比一下
         * 看看是不是一样,如果用户的帐号密码与数据库中查出来的数据一样,那么本次登录成功
         * 否则就是你密码输入错误
         */
        return new SimpleAuthenticationInfo(clientUsername, passwordFromDB , getName());
    }

二.配置文件
在配置文件中,引入我们编写的realm。
myRealm = com.safesoft.DefaultRealm 表示 创建一个DefaultRealm实例,其引入名为myRealm。
在securityManager对象里面使用$引入此Realm类的实例.

[main]
myRealm=com.safesoft.DefaultRealm
securityManager.realms=$myRealm
[users]
jay=123456

下面编写一个测试用例,在subject.login(token);处打一个断点,可进行源码追踪。

public class AuthencateTest {
    @Test
    public void test() {
        //读取配置文件,相当于在加载数据源
        Factory<SecurityManager> factory =
                new IniSecurityManagerFactory("classpath:shiro.ini");
        //SecurityManager 是Shiro内部的底层实现,几乎所有功能都由其实现
        SecurityManager sm = factory.getInstance();
        //SecurityUtils是一个工具,方便用户调用,它封装了SecurityManager
        SecurityUtils.setSecurityManager(sm);
        //生成一个SecurityManager的门面类,即Subject。
        Subject subject = SecurityUtils.getSubject();
        //封装用户的数据
        UsernamePasswordToken token = new UsernamePasswordToken("jay", "123456");
        //Subject接收到的方法参数,最终将会传到SecurityManager中进行验证
        //将用户的数据token 最终传递到Realm中进行对比
        subject.login(token);
        //判断本帐号是否已经被认证
        Assert.assertEquals(true, subject.isAuthenticated());
    }
}

三.代码追踪
如果你已有相关的Shiro基础,那么相信你已经知道如何使用自定义Realm。如果你还不知道如何在项目中使用自定义Realm,今后的章节中有如何使用Realm的例子,所以不用担心。
现在,我先来通过源码分析一下认证的基本流程。
(1)通过Debugger模式追踪源码subject.login(token) 发现。首先是进入Subject接口的默认实现类。果然,Subject将用户的用户名密码委托给了securityManager去做。
在这里插入图片描述
(2)然后,securityManager说:“卧槽,认证器authenticator小弟,听说你的大学学的专业就是认证呀,那么这个认证的任务就交给你咯”。遂将用户的token委托给内部认证组件authenticator去做
在这里插入图片描述
(3)事实上,securityManager的内部组件一个比一个懒。内部认证组件authenticator说:“你们传过来的token我需要拿去跟数据源Realm做对比,这样吧,这个光荣的任务就交给Realm你去做吧”。Realm对象:“MMP”。
在这里插入图片描述
(4)Realm在接到内部认证组件authenticator组件后很伤心,最后对电脑前的你说:“大兄弟,对不住了,你去实现一下呗”。从图中的方法体中可以看到,当前对象是Realm类对象,即将调用的方法是doGetAuthenticationInfo(token)。而这个方法,就是你即将要重写的方法。如果帐号密码通过了,那么返回一个认证成功的info凭证。如果认证失败,抛出一个异常就好了。你说:“什么?最终还是劳资来认证?”没错,就是苦逼的你去实现了,谁叫你是程序猿呢。所以,你不得不查询一下数据库,重写doGetAuthenticationInfo方法,查出来正确的帐号密码,返回一个正确的凭证info。
在这里插入图片描述
(5)好了,这个时候你自己编写了一个类,继承了AuthorizingRealm,并实现了上述doGetAuthenticationInfo方法。你在doGetAuthenticationInfo中编写了查询数据库的代码,并将数据库中存放的用户名与密码封装成了一个AuthenticationInfo对象返回。可以看到下图中,info这个对象是有值的,说明从数据库中查询出来了正确的帐号密码。
在这里插入图片描述
那么,接下来就很简单了。把用户输入的帐号密码与刚才你从数据库中查出来的帐号密码对比一下即可。token封装着用户的帐号密码,AuthenticationInfo封装着从数据库中查询出来的帐号密码。再往下追踪一下代码,最终到了下图中的核心区域。如果没有报异常,说明本次登录成功。
在这里插入图片描述
四.认证流梳理
首先将用户名、密码封装成token。

Subject门面获取到用户表示是token。传递到内部的SecurityManager中。

SecurityManager调用内部组件authenticator去验证。

authenticator将token传递到Realm中去。

最终由你将数据库中的数据查询出来,放到Readlm中去。shiro将会分析用户输入的token是否与数据库中查出来的一致。

再回来来看这张图,把下面的“5”理解成我们重写的Realm即可。
在这里插入图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spring Boot 是一个用于创建和部署独立、生产级别的 Spring 应用程序的框架,而 Apache Shiro 是一个强大且易于使用的 Java 安全框架,提供了认证、授权、加密和会话管理等功能。 在 Spring Boot 应用程序中集成 Shiro,可以通过添加 Shiro Spring Boot Starter 依赖项来实现。此外,您需要配置 Shiro 相关的 Bean,例如 SecurityManager、Realm、Filter 等。您可以使用 Shiro 提供的注解和过滤器来保护您的应用程序资源,并使用 Shiro 提供的身份验证和授权功能来确保只有授权用户才能访问受保护的资源。 总的来说,Spring Boot 集成 Shiro 可以为应用程序提供强大的安全性能和灵活性,使得应用程序开发更加简便和高效。 ### 回答2: 在Spring Boot中集成Shiro可以通过以下步骤完成: 1. 导入相关依赖:在pom.xml文件中添加Shiro和Spring Boot相关的依赖。 2. 创建Shiro配置类:创建一个继承ShiroWebFilterConfiguration的配置类,用于配置Shiro的各种参数和过滤器等。 3. 配置Shiro过滤器链:在上一步创建的配置类中,通过@Bean注解创建ShiroFilterFactoryBean对象,并设置它的相关属性,例如登录url、未授权url等。 4. 创建Realm类:创建一个自定义Realm类,继承AuthorizingRealm,并实现其抽象方法,用于进行身份认证和权限授权。 5. 注册Realm类:在上一步创建的配置类中,通过@Bean注解创建Realm对象,并将其注册到SecurityManager中。 6. 配置Shiro安全管理器:在上一步创建的配置类中,通过@Bean注解创建DefaultWebSecurityManager对象,并设置其相关属性,例如Realm。 7. 配置Spring Boot的安全管理器:创建一个继承自WebSecurityConfigurerAdapter的配置类,覆盖configure方法,将上一步创建的SecurityManager对象设置到WebSecurity中。 8. 配置登录、注销等页面:在application.properties或application.yml文件中配置登录页面、注销页面等。 9. 编写登录页面:创建一个登录页面,用于接收用户输入的用户名和密码。 10. 编写业务代码:在业务代码中使用Shiro的注解进行权限控制,例如@RequiresAuthentication、@RequiresPermissions等。 以上就是在Spring Boot中集成Shiro的大致步骤,通过配置Shiro过滤器链、创建自定义Realm类和安全管理器等,可以实现身份认证和权限控制功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值