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

来源:互联网 发布:js复选框取消选中事件 编辑:程序博客网 时间:2024/04/30 11:30

在使用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的代码

这样就完成了交互


0 0
原创粉丝点击