- AbstractShiroFilter 中执行流程
-
Throwable t = null; try { // 包装 request 和 response final ServletRequest request = prepareServletRequest(servletRequest, servletResponse, chain); final ServletResponse response = prepareServletResponse(request, servletResponse, chain); // 创建 subject final Subject subject = createSubject(request, response); //noinspection unchecked // 由subject执行任务 subject.execute(new Callable() { public Object call() throws Exception { updateSessionLastAccessTime(request, response); executeChain(request, response, chain); return null; } }); } catch (ExecutionException ex) { t = ex.getCause(); } catch (Throwable throwable) { t = throwable; }
- 实际创建subject 过程, 由WebSubject Builder 来构建
protected WebSubject createSubject(ServletRequest request, ServletResponse response) {
return new WebSubject.Builder(getSecurityManager(), request, response).buildWebSubject();
}
- 其创建过程上下问,subjectContext
// 父类构造方法,主要创建一个subjectContext, 实际调用了子类的创建了webSubjectContext,
// 在Context上下文中设置securityManager,request, response
public Builder(SecurityManager securityManager) {
if (securityManager == null) {
throw new NullPointerException("SecurityManager method argument cannot be null.");
}
this.securityManager = securityManager;
this.subjectContext = newSubjectContextInstance();
if (this.subjectContext == null) {
throw new IllegalStateException("Subject instance returned from 'newSubjectContextInstance' " +
"cannot be null.");
}
this.subjectContext.setSecurityManager(securityManager);
}
public Builder(SecurityManager securityManager, ServletRequest request, ServletResponse response) {
super(securityManager);
if (request == null) {
throw new IllegalArgumentException("ServletRequest argument cannot be null.");
}
if (response == null) {
throw new IllegalArgumentException("ServletResponse argument cannot be null.");
}
// 在context 上下文中设置请求和回应
setRequest(request);
setResponse(response);
}
- 构建由securityManager 代理构建
// 有父build 创建
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;
}
// 父类转交给securityManager 通过上下文创建
public Subject buildSubject() {
return this.securityManager.createSubject(this.subjectContext);
}
securityManager 通过上下文创建
public Subject createSubject(SubjectContext subjectContext) {
// 重新复制一份上下文,不修改原来参数中的上下文,有subjectContext /webSubjectContext
//create a copy so we don't modify the argument's backing map:
SubjectContext context = copy(subjectContext);
// 确保上下文中有securityManager,如果没有则新增加一个
//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);
//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);
return subject;
}
// 解析sesssion , 先从 上下文中获取,如果没有则从sessionManager 中查询
@SuppressWarnings({"unchecked"})
protected SubjectContext resolveSession(SubjectContext context) {
// 先从 上下文中获取
if (context.resolveSession() != null) {
log.debug("Context already contains a session. Returning.");
return context;
}
try {
//Context couldn't resolve it directly, let's see if we can since we have direct access to
//the session manager:
Session session = resolveContextSession(context);
// 如果sessionManager 中有则设置到上下文中
if (session != null) {
context.setSession(session);
}
} catch (InvalidSessionException e) {
log.debug("Resolved SubjectContext context session is invalid. Ignoring and creating an anonymous " +
"(session-less) Subject instance.", e);
}
return context;
}
// 从sessionManager 中获取session
protected Session resolveContextSession(SubjectContext context) throws InvalidSessionException {
// 从上下文中中获取sessionKey
SessionKey key = getSessionKey(context);
if (key != null) {
// 从sessionManager 中和去session
return getSession(key);
}
return null;
}
// 如果是webSubjectContext则新建webSessionKey, 交由web
protected SessionKey getSessionKey(SubjectContext context) {
if (WebUtils.isWeb(context)) {
Serializable sessionId = context.getSessionId();
ServletRequest request = WebUtils.getRequest(context);
ServletResponse response = WebUtils.getResponse(context);
return new WebSessionKey(sessionId, request, response);
} else {
// 直接冲上下文中获取sessionKey
return super.getSessionKey(context);
}
}
// 通过sessionKey 获取session, 交由sessionManager 获取session
public Session getSession(SessionKey key) throws SessionException {
return this.sessionManager.getSession(key);
}
// ServletContainerSessionManager 的实现 直接代理httpSession
public Session getSession(SessionKey key) throws SessionException {
if (!WebUtils.isHttp(key)) {
String msg = "SessionKey must be an HTTP compatible implementation.";
throw new IllegalArgumentException(msg);
}
HttpServletRequest request = WebUtils.getHttpRequest(key);
Session session = null;
HttpSession httpSession = request.getSession(false);
if (httpSession != null) {
session = createSession(httpSession, request.getRemoteHost());
}
return session;
}
// 解析
protected SubjectContext resolvePrincipals(SubjectContext context) {
// 容器解析 principal 如果没有则成记住我中获取
PrincipalCollection principals = context.resolvePrincipals();
if (isEmpty(principals)) {
log.trace("No identity (PrincipalCollection) found in the context. Looking for a remembered identity.");
principals = getRememberedIdentity(context);
if (!isEmpty(principals)) {
log.debug("Found remembered PrincipalCollection. Adding to the context to be used " +
"for subject construction by the SubjectFactory.");
context.setPrincipals(principals);
} else {
log.trace("No remembered identity found. Returning original context.");
}
}
return context;
}
// 上下文中解析pricipal, 先上下文中是否直接存储,
public PrincipalCollection resolvePrincipals() {
// 上下文中直接存储
PrincipalCollection principals = getPrincipals();
if (isEmpty(principals)) {
// 上下文中认证信息中存储的
//check to see if they were just authenticated:
AuthenticationInfo info = getAuthenticationInfo();
if (info != null) {
principals = info.getPrincipals();
}
}
// 已有subject中的中的
if (isEmpty(principals)) {
Subject subject = getSubject();
if (subject != null) {
principals = subject.getPrincipals();
}
}
// session中的
if (isEmpty(principals)) {
//try the session:
Session session = resolveSession();
if (session != null) {
principals = (PrincipalCollection) session.getAttribute(PRINCIPALS_SESSION_KEY);
}
}
return principals;
}
// 交由subjectFactoury 来创建,实际就是上下问中的属性,如果没有可能从session 中找
protected Subject doCreateSubject(SubjectContext context) {
return getSubjectFactory().createSubject(context);
}