首页技术文章正文

Shiro如何实现Realm接口?

更新时间:2020-08-14 来源:黑马程序员 浏览量:

【1】Realm接口

1597386494848_Realm接口01.jpg


所以,一般在真实的项目中,我们不会直接实现Realm接口,我们一般的情况就是直接继承AuthorizingRealm,能够继承到认证与授权功能,它需要强制重写两个方法。

public class DefinitionRealm extends AuthorizingRealm {
 
    /**
	 * @Description 认证
	 * @param authcToken token对象
	 * @return 
	 */
	public abstract AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) {
        return null;
    }

	/**
	 * @Description 鉴权
	 * @param principals 令牌
	 * @return
	 */
	public abstract AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals){
        return null;
    }
}


【2】自定义Realm

【2.1】需求

1、自定义Realm,取得密码用于比较。

【2.2】实现

【2.2.1】创建项目

shiro-day01-02realm

1597386505185_Realm接口02.jpg


【2.2.2】定义SecurityService

SecurityService

package com.itheima.shiro.service;

/**
 * @Description:权限服务接口
 */
public interface SecurityService {

    /**
     * @Description 查找密码按用户登录名
     * @param loginName 登录名称
     * @return
     */
    String findPasswordByLoginName(String loginName);
}


SecurityServiceImpl

package com.itheima.shiro.service.impl;

import com.itheima.shiro.service.SecurityService;

/**
 * @Description:权限服务层
 */
public class SecurityServiceImpl implements SecurityService {

    @Override
    public String findPasswordByLoginName(String loginName) {
        return "123";
    }
}


【2.2.3】定义DefinitionRealm

package com.itheima.shiro.realm;

import com.itheima.shiro.service.SecurityService;
import com.itheima.shiro.service.impl.SecurityServiceImpl;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

/**
 * @Description:声明自定义realm
 */
public class DefinitionRealm extends AuthorizingRealm {

    /**
     * @Description 认证接口
     * @param token 传递登录token
     * @return
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //从AuthenticationToken中获得登录名称
        String loginName = (String) token.getPrincipal();
        SecurityService securityService = new SecurityServiceImpl();
        String password = securityService.findPasswordByLoginName(loginName);
        if ("".equals(password)||password==null){
            throw new UnknownAccountException("账户不存在");
        }
        //传递账号和密码
        return  new SimpleAuthenticationInfo(loginName,password,getName());
    }


    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }

}


【2.2.4】编辑shiro.ini

#声明自定义的realm,且为安全管理器指定realms
[main]
definitionRealm=com.itheima.shiro.realm.DefinitionRealm
securityManager.realms=$definitionRealm
#声明用户账号
#[users]
#jay=123


【3】认证源码跟踪

(1)通过debug模式追踪源码subject.login(token) 发现。首先是进入Subject接口的默认实现类。果然,Subject将用户的用户名密码委托给了securityManager去做。

1597386632831_Realm接口03.jpg


(2)然后,securityManager说:“卧槽,认证器authenticator小弟,听说你的大学学的专业就是认证呀,那么这个认证的任务就交给你咯”。遂将用户的token委托给内部认证组件authenticator去做。

1597386641661_Realm接口04.jpg


(3)事实上,securityManager的内部组件一个比一个懒。内部认证组件authenticator说:“你们传过来的token我需要拿去跟数据源Realm做对比,这样吧,这个光荣的任务就交给Realm你去做吧”。Realm对象:“一群大懒虫!”。

1597386651080_Realm接口05.jpg


(4)Realm在接到内部认证组件authenticator组件后很伤心,最后对电脑前的你说:“大兄弟,对不住了,你去实现一下呗”。从图中的方法体中可以看到,当前对象是Realm类对象,即将调用的方法是doGetAuthenticationInfo(token)。而这个方法,就是你即将要重写的方法。如果帐号密码通过了,那么返回一个认证成功的info凭证。如果认证失败,抛出一个异常就好了。你说:“什么?最终还是劳资来认证?”没错,就是苦逼的你去实现了,谁叫你是程序猿呢。所以,你不得不查询一下数据库,重写doGetAuthenticationInfo方法,查出来正确的帐号密码,返回一个正确的凭证info。

1597386660293_Realm接口06.jpg


(5)好了,这个时候你自己编写了一个类,继承了AuthorizingRealm,并实现了上述doGetAuthenticationInfo方法。你在doGetAuthenticationInfo中编写了查询数据库的代码,并将数据库中存放的用户名与密码封装成了一个AuthenticationInfo对象返回。可以看到下图中,info这个对象是有值的,说明从数据库中查询出来了正确的帐号密码。

1597386670069_Realm接口07.jpg


(6)那么,接下来就很简单了。把用户输入的帐号密码与刚才你从数据库中查出来的帐号密码对比一下即可。token封装着用户的帐号密码,AuthenticationInfo封装着从数据库中查询出来的帐号密码。再往下追踪一下代码,最终到了下图中的核心区域。如果没有报异常,说明本次登录成功。

1597386678516_Realm接口08.jpg



猜你喜欢:

Shiro入门教程:如何实现身份认证?

shiro是啥?Shiro的核心组件介绍

Shiro特点和运行原理详细介绍

Java软件高级工程师培训课程

分享到:
在线咨询 我要报名
和我们在线交谈!