调用顺序
>> AbstractShiroFilter.doFilterInternal(ServletRequest, ServletResponse, FilterChain)
>> AbstractShiroFilter.createSubject(ServletRequest, ServletResponse)
>> WebSubject.Builder.buildWebSubject()
>> Subject.Builder.buildSubject()
>> SecurityManager.createSubject(SubjectContext)
具体流程
AbstractShiroFilter.doFilterInternal() 方法中调用了 createSubject(),观察这个方法。
protected WebSubject createSubject(ServletRequest request, ServletResponse response) {
return new WebSubject.Builder(getSecurityManager(), request, response).buildWebSubject();
}
该方法使用了 WebSubject,可以推测,它需要创建一个 Web 类型的 Subject。
PS:使用 Builder 设计模式。
下面观察 WebSubject.Builder.buildWebSubject() 源码:
public WebSubject buildWebSubject() {
Subject subject = super.buildSubject();
if (!(subject instanceof WebSubject)) {
String msg = "Subject implementation returned from the SecurityManager was not a "
+ WebSubject.class.getName() + " implementation. Please ensure a Web-enabled SecurityManager "
+ "has been configured and made available to this builder.";
throw new IllegalStateException(msg);
}
return (WebSubject) subject;
}
上面方法调用了 super.buildSubject(),继续观察 super.buildSubject():
public Subject buildSubject() {
return this.securityManager.createSubject(this.subjectContext);
}
至此,我们发现,原来是 secuirtyManager 创建了 Subject。
其实在 Shiro-Spring Web 框架中,securityManager 的实现类只可能是 DefaultWebSecurityManager(因为只有这个实现类是 WebSecurityManager 接口的实现类),那我们下面就只看它的 createSubject() 方法:
public Subject createSubject(SubjectContext subjectContext) {
SubjectContext context = copy(subjectContext);
context = ensureSecurityManager(context);
context = resolveSession(context);
context = resolvePrincipals(context);
Subject subject = doCreateSubject(context);
save(subject);
return subject;
}
见明知意,应该知道,doCreateSubject() 就是创建 Subject 的真正方法:
protected Subject doCreateSubject(SubjectContext context) {
return getSubjectFactory().createSubject(context);
}
方法获取了 SubjectFactory(工厂设计),然后调用了工厂的 createSubject() 方法:
public Subject createSubject(SubjectContext context) {
if (!(context instanceof WebSubjectContext)) {
return super.createSubject(context);
}
WebSubjectContext wsc = (WebSubjectContext) context;
SecurityManager securityManager = wsc.resolveSecurityManager();
Session session = wsc.resolveSession();
boolean sessionEnabled = wsc.isSessionCreationEnabled();
PrincipalCollection principals = wsc.resolvePrincipals();
boolean authenticated = wsc.resolveAuthenticated();
String host = wsc.resolveHost();
ServletRequest request = wsc.resolveServletRequest();
ServletResponse response = wsc.resolveServletResponse();
return new WebDelegatingSubject(principals, authenticated, host, session, sessionEnabled, request, response,
securityManager);
}
上面的方法主要是以 context 出发,从而获得各种各样的参数,进而传递给 WebDelegatingSubject 构造器。