shiro 多节点

首先,在系统中shiro提供交互的对象是Subject;所以先弄明白subject的生成和保存;

知道shiro是以filter的方式整合到系统中的,那么就查看shiro的filter

shiro 多节点

主要看AbstractShiroFilter的doFilterInternal方法就行了,里面的一部分主要代码

final Subject subject = createSubject(request, response);//这里创建或者从缓存里取subject

//noinspection unchecked
subject.execute(new Callable() {
     public Object call() throws Exception {
          updateSessionLastAccessTime(request, response);//这里更新或者保存session
          executeChain(request, response, chain);
          return null;
         }
});

所以得知每次被拦截都会生成或者提取subject;

createSubject(....)的主要调用代码在DefaultSecurityManager类的createSubject(SubjectContext subjectContext)方法中;

/**
     * This implementation functions as follows:
     * <p/>
     * <ol>
     * <li>Ensures the {@code SubjectContext} is as populated as it can be, using heuristics to acquire
     * data that may not have already been available to it (such as a referenced session or remembered principals).</li>
     * <li>Calls {@link #doCreateSubject(org.apache.shiro.subject.SubjectContext)} to actually perform the
     * {@code Subject} instance creation.</li>
     * <li>calls {@link #save(org.apache.shiro.subject.Subject) save(subject)} to ensure the constructed
     * {@code Subject}'s state is accessible for future requests/invocations if necessary.</li>
     * <li>returns the constructed {@code Subject} instance.</li>
     * </ol>
     *
     * @param subjectContext any data needed to direct how the Subject should be constructed.
     * @return the {@code Subject} instance reflecting the specified contextual data.
     * @see #ensureSecurityManager(org.apache.shiro.subject.SubjectContext)
     * @see #resolveSession(org.apache.shiro.subject.SubjectContext)
     * @see #resolvePrincipals(org.apache.shiro.subject.SubjectContext)
     * @see #doCreateSubject(org.apache.shiro.subject.SubjectContext)
     * @see #save(org.apache.shiro.subject.Subject)
     * @since 1.0
     */
    public Subject createSubject(SubjectContext subjectContext) {
        //create a copy so we don't modify the argument's backing map:
        SubjectContext context = copy(subjectContext);//上下文环境?其实就几个属性

        //ensure that the context has a SecurityManager instance, and if not, add one:
        context = ensureSecurityManager(context);

        //Resolve an associated Session (usually based on a referenced session ID), and place it in the context before
        //sending to the SubjectFactory.  The SubjectFactory should not need to know how to acquire sessions as the
        //process is often environment specific - better to shield the SF from these details:
        context = resolveSession(context);//关联session的方法,如果配置session则会取缓存中的session

        //Similarly, the SubjectFactory should not require any concept of RememberMe - translate that here first
        //if possible before handing off to the SubjectFactory:
        context = resolvePrincipals(context);//关联授权信息

        Subject subject = doCreateSubject(context);

        //save this subject for future reference if necessary:
        //(this is needed here in case rememberMe principals were resolved and they need to be stored in the
        //session, so we don't constantly rehydrate the rememberMe PrincipalCollection on every operation).
        //Added in 1.2:
        save(subject);//保存subject,subject是保存为线程相关的,其实是线程继承相关,所以也就跟容器相关;而授权信息、认证信息也保存在session里

        return subject;
    }

shiro提供获取subject的途径是SecurityUtils.getSubject(),就会返回线程相关的subject。保存的容器被定义为

private static final ThreadLocal<Map<Object, Object>> resources = new InheritableThreadLocalMap<Map<Object, Object>>();

-----------------------------------------------以下是吐槽-----------------------------------------------------

项目要改为支持多节点的部署方式,觉得应该把shiro的session缓存在redis中就行了,于是用了http://www.oschina.net/p/shiro-redis(其实一直在用的)。把项目部署到两个tomcat后,一直登陆验证模块就失效了,不是说不走shiro拦截了,这个肯定是经过的。只是登陆的流程中两台tomcat都有接受到请求。调试的结果发现在一台tomcat上成功登陆的信息,在另一个tomcat上获取为空.....各种不明白,就这样花了我两天时间,,,,,,,没搞定。。。嗯,还好有高手指点。问题是shiro-redis的提供了本地缓存。。。。。。。。。。。无语,,,无语中把shiro-redis的sessionDAO自己实现一个,自己实现的是直接从redis中获取shiro的信息,不用什么本地缓存。

------------------------------------------以下是待解决的问题--------------------------------------------------------

在开启session中发现,认证信息也是可以缓存的,就是AuthenticationInfo也是可以放入缓存中的,不必每次登陆都从数据库中获取数据进行认证。调试得知缓存认证是根据密码匹配的;但是如何刷新还没查看

------------------------------------------------05.07---------------------------------------------

以下来说明上面待解决的问题;

如果开启了认证和授权的缓存.

AuthenticatingRealm.cacheAuthenticationInfoIfPossible方法缓存认证信息;

AuthorizingRealm.getAuthorizationInfo方法缓存和获取授权信息;

注意认证或是授权缓存的key值是否有对象的hash值,如果有每次都保存同一个账号的多个缓存值;

授权缓存的key是根据Principal类的toString得到的

你可能感兴趣的:(shiro 多节点)