Shiro中自定义Realm的作用(FormAuthenticationFilter和PermissionAuthorizationFilter)以及源码解析

在使用shiro时都会自定义一个Realm,Realm的作用就是提供给shiro和数据库进行交互的一个中间层,这样shiro能够帮助我们处理登录(成功、失败),授权,访问控制等功能,但是用户登录的用户信息和用户具体的权限信息是shiro未知的,所以需要每次都请求Realm,由Realm提供

比如授权的流程

使用PermissionAuthorizationFilter
在xml中设置权限
${adminPath}/areaInfo = perms[area:query,area:add]
当发出这个请求(已经验证通过)被PermisssionsAuthorizationFilter拦截,发现需要权限
会调用realm的doGetAuthorizationInfo获取数据库中正确的数据库权限(所以realm的作用 就是查询,剩下的活是shiro的)
PermissionAuthorizationFilter对请求的url对应的权限和从realm中获取的权限进行对比

登录和授权,realm只提供查找返回,不提供逻辑处理,都由shiro解决

拿login来分析

当请求信息是login时,FormAuthenticationFilter会对其进行拦截,解析是不是login请求,并处理

//FormAuthenticationFilter 判断是不是一个login请求
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        if (isLoginRequest(request, response)) {
            if (isLoginSubmission(request, response)) {
                if (log.isTraceEnabled()) {
                    log.trace("Login submission detected.  Attempting to execute login.");
                }
                return executeLogin(request, response);
            } else {
                if (log.isTraceEnabled()) {
                    log.trace("Login page view.");
                }
                //allow them to see the login page ;)
                return true;
            }
        } else {
            if (log.isTraceEnabled()) {
                log.trace("Attempting to access a path which requires authentication.  Forwarding to the " +
                        "Authentication url [" + getLoginUrl() + "]");
            }

            saveRequestAndRedirectToLogin(request, response);
            return false;
        }
    }
可以看到如果是login请求会执行executeLogin方法

//AuthenticatingFilter 此处找到subject.login(token)操作
    protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
        AuthenticationToken token = createToken(request, response);
        if (token == null) {
            String msg = "createToken method implementation returned null. A valid non-null AuthenticationToken " +
                    "must be created in order to execute a login attempt.";
            throw new IllegalStateException(msg);
        }
        try {
            Subject subject = getSubject(request, response);
            subject.login(token);//调用了realm
            return onLoginSuccess(token, subject, request, response);
        } catch (AuthenticationException e) {
            return onLoginFailure(token, e, request, response);
        }
    }
//DelegatingSubject
    public void login(AuthenticationToken token) throws AuthenticationException {
        clearRunAsIdentitiesInternal();
        Subject subject = securityManager.login(this, token);//调用了realm

        PrincipalCollection principals;

        String host = null;

        if (subject instanceof DelegatingSubject) {
            DelegatingSubject delegating = (DelegatingSubject) subject;
            //we have to do this in case there are assumed identities - we don't want to lose the 'real' principals:
            principals = delegating.principals;
            host = delegating.host;
        } else {
            principals = subject.getPrincipals();
        }

        if (principals == null || principals.isEmpty()) {
            String msg = "Principals returned from securityManager.login( token ) returned a null or " +
                    "empty value.  This value must be non null and populated with one or more elements.";
            throw new IllegalStateException(msg);
        }
        this.principals = principals;
        this.authenticated = true;
        if (token instanceof HostAuthenticationToken) {
            host = ((HostAuthenticationToken) token).getHost();
        }
        if (host != null) {
            this.host = host;
        }
        Session session = subject.getSession(false);
        if (session != null) {
            this.session = decorate(session);
        } else {
            this.session = null;
        }
    }
由securityManager进行登录

重点来了

    public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException {
        AuthenticationInfo info;
        try {
            info = authenticate(token);
        } catch (AuthenticationException ae) {
            try {
                onFailedLogin(token, ae, subject);
            } catch (Exception e) {
                if (log.isInfoEnabled()) {
                    log.info("onFailedLogin method threw an " +
                            "exception.  Logging and propagating original AuthenticationException.", e);
                }
            }
            throw ae; //propagate
        }

        Subject loggedIn = createSubject(token, info, subject);

        onSuccessfulLogin(token, info, loggedIn);

        return loggedIn;
    }


我们发现public class DefaultSecurityManager extends SessionsSecurityManager 

也就是上面的securityManager的实现类中调用的login,这里就是反悔了一个AuthenticationInfo对象,其中autheticate(token)这个方法继续跟踪到最后就会到达我们的自定义realm中的doGetAuthenticationInfo方法

所以这个info主要是为这行代码服务的

Subject loggedIn = createSubject(token, info, subject);
即生成subject的代码

这样就完成了交互


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值