Spring Shiro基础组件 Subject

相关阅读

简介

表示应用程序中用户的状态和安全操作,是Shiro的单用户安全功能的主要机制;
总是使用SecurityUtils.getSubject()获取当前正在执行的Subject

核心方法

/**
 * 获取应用程序范围内该主题的唯一标识主体
 * 若未登录(匿名),则返回null
 */
Object getPrincipal();

/**
 * 以PrincipalCollection形式返回该主题的主体集合
 */
PrincipalCollection getPrincipals();

/**
 * 是否包含指定的权限
 */
boolean isPermitted(String permission);

/**
 * 是否包含指定的权限
 */
boolean isPermitted(Permission permission);

/**
 * 是否包含指定的权限列表
 */
boolean[] isPermitted(String... permissions);

/**
 * 是否包含指定的权限集合
 */
boolean[] isPermitted(List<Permission> permissions);

/**
 * 是否包含所有指定的权限列表
 */
boolean isPermittedAll(String... permissions);

/**
 * 是否包含所有指定的权限集合
 */
boolean isPermittedAll(Collection<Permission> permissions);

/**
 * 校验是否包含指定的权限
 */
void checkPermission(String permission) throws AuthorizationException;

/**
 * 校验是否包含指定的权限
 */
void checkPermission(Permission permission) throws AuthorizationException;

/**
 * 校验是否包含所有指定的权限列表
 */
void checkPermissions(String... permissions) throws AuthorizationException;

/**
 * 校验是否包含所有指定的权限集合
 */
void checkPermissions(Collection<Permission> permissions) throws AuthorizationException;

/**
 * 是否包含指定的角色
 */
boolean hasRole(String roleIdentifier);

/**
 * 是否包含指定的角色集合
 */
boolean[] hasRoles(List<String> roleIdentifiers);

/**
 * 是否包含所有指定的角色集合
 */
boolean hasAllRoles(Collection<String> roleIdentifiers);

/**
 * 校验是否包含指定的角色
 */
void checkRole(String roleIdentifier) throws AuthorizationException;

/**
 * 校验是否包含所有指定的角色集合
 */
void checkRoles(Collection<String> roleIdentifiers) throws AuthorizationException;

/**
 * 校验是否包含所有指定的角色列表
 */
void checkRoles(String... roleIdentifiers) throws AuthorizationException;

/**
 * 登录
 * 登录失败,会抛出AuthenticationException异常
 * 登录成功,随提交的主体/凭证一起的账户信息会和该主题关联,并且安静地返回,且getPrincipal()将非null,isAuthenticated()将为true
 */
void login(AuthenticationToken token) throws AuthenticationException;

/**
 * 是否身份验证通过
 */
boolean isAuthenticated();

/**
 * 是否在上一个会话中成功登录过
 * 通常等效于:getPrincipal() != null && !isAuthenticated()
 * 一旦成功登录,就不再视为被记住
 * 应用程序的许多部分可以根据isRemembered()指定特定的逻辑,但涉及高度敏感的操作必须根据isAuthenticated()
 */
boolean isRemembered();

/**
 * 获取该主题绑定的Session
 * 若未绑定,则创建新Session绑定后返回
 */
Session getSession();

/**
 * 获取该主题绑定的Session
 * 若未绑定,则根据create判断是否创建新Session
 */
Session getSession(boolean create);

/**
 * 登出
 * 登出后,和该主题相关的信息,如Session/身份验证信息都会被移除
 */
void logout();

/**
 * 将指定的Callable任务和该主题关联,并在当前线程上执行
 */
<V> V execute(Callable<V> callable) throws ExecutionException;

/**
 * 将指定的Runnable任务和该主题关联,并在当前线程上执行
 * 此方法主要用于执行现有/遗留的Runnable实现,新代码推荐使用execute(Callable),因为其支持返回值和捕捉异常
 */
void execute(Runnable runnable);

/**
 * 返回一个和指定Callable任务匹配,并且在该主题身份下保留和执行的Callable任务
 * 返回的Callable任务可以交给ExecutorService执行
 * 这确保Securityutils.getSubject()和相关功能在执行返回的Callable任务的线程上正常运行
 */
<V> Callable<V> associateWith(Callable<V> callable);

/**
 * 返回一个和指定Runnable任务匹配,并且在该主题身份下保留和执行的Runnable任务
 * 返回的Runnable任务可以交给ExecutorService执行
 * 这确保Securityutils.getSubject()和相关功能在执行返回的Runnable任务的线程上正常运行
 * 如果希望返回值或者捕捉异常,强烈建议使用associateWith(Callable)
 */
Runnable associateWith(Runnable runnable);

/**
 * 允许已有身份的主题以其他身份运行
 */
void runAs(PrincipalCollection principals) throws NullPointerException, IllegalStateException;

/**
 * 判断该主题是否以其他身份运行
 */
boolean isRunAs();

/**
 * 当该主题以其他身份运行时,返回之前的已有身份(可能也是其他身份);否则返回null
 */
PrincipalCollection getPreviousPrincipals();

/**
 * 释放当前运行的其他身份,并恢复到之前的已有身份(可能也是其他身份)
 * 如果当前以其他身份运行就返回该身份,否则返回null
 */
PrincipalCollection releaseRunAs();

静态内部类Builder
构造器设计模式实现,简化Subject实例的创建;
核心方法
// 上下文,共SecurityManager创建Subject实例
private final SubjectContext subjectContext;

// 安全管理器
private final SecurityManager securityManager;

/**
 * 构造方法
 */
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);
}

/**
 * 创建Subject实例
 */
public Subject buildSubject() {
    return this.securityManager.createSubject(this.subjectContext);
}

实现子类

public interface Subject
    public class DelegatingSubject implements Subject
        public class WebDelegatingSubject extends DelegatingSubject implements WebSubject
    public interface WebSubject extends Subject, RequestPairSource
        public class WebDelegatingSubject extends DelegatingSubject implements WebSubject

DelegatingSubject

简介

将方法调用委托给底层的SecurityManager实例来进行安全检查,本质上是SecurityManager的代理;

核心方法

private static final String RUN_AS_PRINCIPALS_SESSION_KEY =
        DelegatingSubject.class.getName() + ".RUN_AS_PRINCIPALS_SESSION_KEY";
// 主体集合
protected PrincipalCollection principals;
// 鉴权标识
protected boolean authenticated;
// 客户端hostname/ip
protected String host;
// 会话
protected Session session;
// 允许创建会话标识
protected boolean sessionCreationEnabled;
// 安全管理器
protected transient SecurityManager securityManager;

/**
 * 构造方法
 */
public DelegatingSubject(PrincipalCollection principals, boolean authenticated, String host,
                         Session session, boolean sessionCreationEnabled, SecurityManager securityManager) {
    if (securityManager == null) {
        throw new IllegalArgumentException("SecurityManager argument cannot be null.");
    }
    this.securityManager = securityManager;
    this.principals = principals;
    this.authenticated = authenticated;
    this.host = host;
    if (session != null) {
        this.session = decorate(session);
    }
    this.sessionCreationEnabled = sessionCreationEnabled;
}

/**
 * 装饰session,增加额外的处理逻辑
 */
protected Session decorate(Session session) {
    if (session == null) {
        throw new IllegalArgumentException("session cannot be null");
    }
    return new StoppingAwareProxiedSession(session, this);
}

/**
 * 获取主要主体
 */
private Object getPrimaryPrincipal(PrincipalCollection principals) {
    if (!isEmpty(principals)) {
        return principals.getPrimaryPrincipal();
    }
    return null;
}

/**
 * 获取应用程序范围内该主题的唯一标识主体
 */
public Object getPrincipal() {
    return getPrimaryPrincipal(getPrincipals());
}

/**
 * 以PrincipalCollection形式返回该主题的主体集合
 */
public PrincipalCollection getPrincipals() {
    List<PrincipalCollection> runAsPrincipals = getRunAsPrincipalsStack();
    // 优先使用另外的身份信息
    return CollectionUtils.isEmpty(runAsPrincipals) ? this.principals : runAsPrincipals.get(0);
}

/**
 * 获取另外身份验证信息栈
 */
private List<PrincipalCollection> getRunAsPrincipalsStack() {
    Session session = getSession(false);
    if (session != null) {
        return (List<PrincipalCollection>) session.getAttribute(RUN_AS_PRINCIPALS_SESSION_KEY);
    }
    return null;
}

/**
 * 是否包含指定的权限
 */
public boolean isPermitted(String permission) {
    return hasPrincipals() && securityManager.isPermitted(getPrincipals(), permission);
}

/**
 * 是否包含指定的权限
 */
public boolean isPermitted(Permission permission) {
    return hasPrincipals() && securityManager.isPermitted(getPrincipals(), permission);
}

/**
 * 是否包含指定的权限列表
 */
public boolean[] isPermitted(String... permissions) {
    if (hasPrincipals()) {
        return securityManager.isPermitted(getPrincipals(), permissions);
    } else {
        return new boolean[permissions.length];
    }
}

/**
 * 是否包含指定的权限集合
 */
public boolean[] isPermitted(List<Permission> permissions) {
    if (hasPrincipals()) {
        return securityManager.isPermitted(getPrincipals(), permissions);
    } else {
        return new boolean[permissions.size()];
    }
}

/**
 * 是否包含所有指定的权限列表
 */
public boolean isPermittedAll(String... permissions) {
    return hasPrincipals() && securityManager.isPermittedAll(getPrincipals(), permissions);
}

/**
 * 是否包含所有指定的权限集合
 */
public boolean isPermittedAll(Collection<Permission> permissions) {
    return hasPrincipals() && securityManager.isPermittedAll(getPrincipals(), permissions);
}

/**
 * 校验身份验证信息
 */
protected void assertAuthzCheckPossible() throws AuthorizationException {
    if (!hasPrincipals()) {
        String msg = "This subject is anonymous - it does not have any identifying principals and " +
                "authorization operations require an identity to check against.  A Subject instance will " +
                "acquire these identifying principals automatically after a successful login is performed " +
                "be executing " + Subject.class.getName() + ".login(AuthenticationToken) or when 'Remember Me' " +
                "functionality is enabled by the SecurityManager.  This exception can also occur when a " +
                "previously logged-in Subject has logged out which " +
                "makes it anonymous again.  Because an identity is currently not known due to any of these " +
                "conditions, authorization is denied.";
        throw new UnauthenticatedException(msg);
    }
}

/**
 * 校验是否包含指定的权限
 */
public void checkPermission(String permission) throws AuthorizationException {
    assertAuthzCheckPossible();
    securityManager.checkPermission(getPrincipals(), permission);
}

/**
 * 校验是否包含指定的权限
 */
public void checkPermission(Permission permission) throws AuthorizationException {
    assertAuthzCheckPossible();
    securityManager.checkPermission(getPrincipals(), permission);
}

/**
 * 校验是否包含所有指定的权限列表
 */
public void checkPermissions(String... permissions) throws AuthorizationException {
    assertAuthzCheckPossible();
    securityManager.checkPermissions(getPrincipals(), permissions);
}

/**
 * 校验是否包含所有指定的权限集合
 */
public void checkPermissions(Collection<Permission> permissions) throws AuthorizationException {
    assertAuthzCheckPossible();
    securityManager.checkPermissions(getPrincipals(), permissions);
}

/**
 * 是否包含指定的角色
 */
public boolean hasRole(String roleIdentifier) {
    return hasPrincipals() && securityManager.hasRole(getPrincipals(), roleIdentifier);
}

/**
 * 是否包含指定的角色集合
 */
public boolean[] hasRoles(List<String> roleIdentifiers) {
    if (hasPrincipals()) {
        return securityManager.hasRoles(getPrincipals(), roleIdentifiers);
    } else {
        return new boolean[roleIdentifiers.size()];
    }
}

/**
 * 是否包含所有指定的角色集合
 */
public boolean hasAllRoles(Collection<String> roleIdentifiers) {
    return hasPrincipals() && securityManager.hasAllRoles(getPrincipals(), roleIdentifiers);
}

/**
 * 校验是否包含指定的角色
 */
public void checkRole(String role) throws AuthorizationException {
    assertAuthzCheckPossible();
    securityManager.checkRole(getPrincipals(), role);
}

/**
 * 校验是否包含所有指定的角色列表
 */
public void checkRoles(String... roleIdentifiers) throws AuthorizationException {
    assertAuthzCheckPossible();
    securityManager.checkRoles(getPrincipals(), roleIdentifiers);
}

/**
 * 校验是否包含所有指定的角色集合
 */
public void checkRoles(Collection<String> roles) throws AuthorizationException {
    assertAuthzCheckPossible();
    securityManager.checkRoles(getPrincipals(), roles);
}

/**
 * 登录
 */
public void login(AuthenticationToken token) throws AuthenticationException {
    clearRunAsIdentitiesInternal();
    // 获取登录后绑定的Subject
    Subject subject = securityManager.login(this, token);

    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;
    }
}

/**
 * 是否身份验证通过
 */
public boolean isAuthenticated() {
    return authenticated && hasPrincipals();
}

/**
 * 是否在上一个会话中成功登录过
 */
public boolean isRemembered() {
    PrincipalCollection principals = getPrincipals();
    return principals != null && !principals.isEmpty() && !isAuthenticated();
}

/**
 * 获取该主题绑定的Session
 * 若未绑定,则创建新Session绑定后返回
 */
public Session getSession() {
    return getSession(true);
}

/**
 * 获取该主题绑定的Session
 * 若未绑定,则根据create判断是否创建新Session
 */
public Session getSession(boolean create) {
    if (log.isTraceEnabled()) {
        log.trace("attempting to get session; create = " + create +
                "; session is null = " + (this.session == null) +
                "; session has id = " + (this.session != null && session.getId() != null));
    }

    if (this.session == null && create) {

        //added in 1.2:
        if (!isSessionCreationEnabled()) {
            // 不允许创建session
            String msg = "Session creation has been disabled for the current subject.  This exception indicates " +
                    "that there is either a programming error (using a session when it should never be " +
                    "used) or that Shiro's configuration needs to be adjusted to allow Sessions to be created " +
                    "for the current Subject.  See the " + DisabledSessionException.class.getName() + " JavaDoc " +
                    "for more.";
            throw new DisabledSessionException(msg);
        }

        log.trace("Starting session for host {}", getHost());
        SessionContext sessionContext = createSessionContext();
        Session session = this.securityManager.start(sessionContext);
        this.session = decorate(session);
    }
    return this.session;
}

/**
 * 创建session上下文
 */
protected SessionContext createSessionContext() {
    SessionContext sessionContext = new DefaultSessionContext();
    if (StringUtils.hasText(host)) {
        sessionContext.setHost(host);
    }
    return sessionContext;
}

/**
 * 清除另外身份验证信息
 */
private void clearRunAsIdentitiesInternal() {
    //try/catch added for SHIRO-298
    try {
        clearRunAsIdentities();
    } catch (SessionException se) {
        log.debug("Encountered session exception trying to clear 'runAs' identities during logout.  This " +
                "can generally safely be ignored.", se);
    }
}

/**
 * 登出
 */
public void logout() {
    try {
        // 清除身份验证信息
        clearRunAsIdentitiesInternal();
        // 登出
        this.securityManager.logout(this);
    } finally {
        // 清空数据
        this.session = null;
        this.principals = null;
        this.authenticated = false;
        //Don't set securityManager to null here - the Subject can still be
        //used, it is just considered anonymous at this point.  The SecurityManager instance is
        //necessary if the subject would log in again or acquire a new session.  This is in response to
        //https://issues.apache.org/jira/browse/JSEC-22
        //this.securityManager = null;
    }
}

/**
 * 清除session
 */
private void sessionStopped() {
    this.session = null;
}

/**
 * 将指定的Callable任务和该主题关联,并在当前线程上执行
 */
public <V> V execute(Callable<V> callable) throws ExecutionException {
    Callable<V> associated = associateWith(callable);
    try {
        return associated.call();
    } catch (Throwable t) {
        throw new ExecutionException(t);
    }
}

/**
 * 将指定的Runnable任务和该主题关联,并在当前线程上执行
 * 此方法主要用于执行现有/遗留的Runnable实现,新代码推荐使用execute(Callable),因为其支持返回值和捕捉异常
 */
public void execute(Runnable runnable) {
    Runnable associated = associateWith(runnable);
    associated.run();
}

/**
 * 返回一个和指定Callable任务匹配,并且在该主题身份下保留和执行的Callable任务
 * 返回的Callable任务可以交给ExecutorService执行
 * 这确保Securityutils.getSubject()和相关功能在执行返回的Callable任务的线程上正常运行
 */
public <V> Callable<V> associateWith(Callable<V> callable) {
    return new SubjectCallable<V>(this, callable);
}

/**
 * 返回一个和指定Runnable任务匹配,并且在该主题身份下保留和执行的Runnable任务
 * 返回的Runnable任务可以交给ExecutorService执行
 * 这确保Securityutils.getSubject()和相关功能在执行返回的Runnable任务的线程上正常运行
 * 如果希望返回值或者捕捉异常,强烈建议使用associateWith(Callable)
 */
public Runnable associateWith(Runnable runnable) {
    // 不支持Thread类型任务
    if (runnable instanceof Thread) {
        String msg = "This implementation does not support Thread arguments because of JDK ThreadLocal " +
                "inheritance mechanisms required by Shiro.  Instead, the method argument should be a non-Thread " +
                "Runnable and the return value from this method can then be given to an ExecutorService or " +
                "another Thread.";
        throw new UnsupportedOperationException(msg);
    }
    return new SubjectRunnable(this, runnable);
}

/**
 * 允许已有身份的主题以其他身份运行
 */
public void runAs(PrincipalCollection principals) {
    if (!hasPrincipals()) {
        // 当前主题没有身份信息
        String msg = "This subject does not yet have an identity.  Assuming the identity of another " +
                "Subject is only allowed for Subjects with an existing identity.  Try logging this subject in " +
                "first, or using the " + Subject.Builder.class.getName() + " to build ad hoc Subject instances " +
                "with identities as necessary.";
        throw new IllegalStateException(msg);
    }
    pushIdentity(principals);
}

/**
 * 判断该主题是否以其他身份运行
 */
public boolean isRunAs() {
    List<PrincipalCollection> stack = getRunAsPrincipalsStack();
    return !CollectionUtils.isEmpty(stack);
}

/**
 * 当该主题以其他身份运行时,返回之前的已有身份((可能也是其他身份);否则返回null
 */
public PrincipalCollection getPreviousPrincipals() {
    // 默认没有其他身份信息
    PrincipalCollection previousPrincipals = null;
    List<PrincipalCollection> stack = getRunAsPrincipalsStack();
    int stackSize = stack != null ? stack.size() : 0;
    if (stackSize > 0) {
        // 存在其他身份信息
        if (stackSize == 1) {
            // 仅存在一个身份信息,则获取自身拥有的身份信息
            previousPrincipals = this.principals;
        } else {
            // 存在超过一个身份信息,则获取上一个身份信息
            //always get the one behind the current:
            assert stack != null;
            previousPrincipals = stack.get(1);
        }
    }
    return previousPrincipals;
}

/**
 * 释放当前运行的其他身份,并恢复到之前的已有身份(可能也是其他身份)
 * 如果当前以其他身份运行就返回该身份,否则返回null
 */
public PrincipalCollection releaseRunAs() {
    return popIdentity();
}

/**
 * 获取身份信息栈
 */
@SuppressWarnings("unchecked")
private List<PrincipalCollection> getRunAsPrincipalsStack() {
    Session session = getSession(false);
    if (session != null) {
        return (List<PrincipalCollection>) session.getAttribute(RUN_AS_PRINCIPALS_SESSION_KEY);
    }
    return null;
}

/**
 * 清除身份信息栈
 */
private void clearRunAsIdentities() {
    Session session = getSession(false);
    if (session != null) {
        session.removeAttribute(RUN_AS_PRINCIPALS_SESSION_KEY);
    }
}

/**
 * 身份信息压栈
 */
private void pushIdentity(PrincipalCollection principals) throws NullPointerException {
    if (isEmpty(principals)) {
        String msg = "Specified Subject principals cannot be null or empty for 'run as' functionality.";
        throw new NullPointerException(msg);
    }
    // 获取身份信息栈
    List<PrincipalCollection> stack = getRunAsPrincipalsStack();
    if (stack == null) {
        stack = new CopyOnWriteArrayList<PrincipalCollection>();
    }
    // 将当前身份信息压栈
    stack.add(0, principals);
    Session session = getSession();
    // 将身份信息栈存在session中
    session.setAttribute(RUN_AS_PRINCIPALS_SESSION_KEY, stack);
}

/**
 * 身份信息出栈
 */
private PrincipalCollection popIdentity() {
    PrincipalCollection popped = null;

    List<PrincipalCollection> stack = getRunAsPrincipalsStack();
    if (!CollectionUtils.isEmpty(stack)) {
        // 栈顶元素出栈
        popped = stack.remove(0);
        Session session;
        if (!CollectionUtils.isEmpty(stack)) {
            // 栈未空,则更新为新栈
            //persist the changed stack to the session
            session = getSession();
            session.setAttribute(RUN_AS_PRINCIPALS_SESSION_KEY, stack);
        } else {
            // 栈空,则清除
            //stack is empty, remove it from the session:
            clearRunAsIdentities();
        }
    }

    return popped;
}

/**
 * 静态内部类,代理session,增加额外的处理逻辑
 */
private class StoppingAwareProxiedSession extends ProxiedSession {

    // 额外的处理逻辑
    private final DelegatingSubject owner;

    private StoppingAwareProxiedSession(Session target, DelegatingSubject owningSubject) {
        super(target);
        owner = owningSubject;
    }

    public void stop() throws InvalidSessionException {
        super.stop();
        // 额外的处理逻辑
        owner.sessionStopped();
    }
}

WebSubject

简介

被当作传入的ServletRequest的结果的Subject实例;

核心方法

/**
 * 创建Subject实例时可访问的ServletRequest
 */
ServletRequest getServletRequest();

/**
 * 创建Subject实例时可访问的ServletResponse
 */
ServletResponse getServletResponse();

静态内部类Builder

简介

继承自Subject.Builder

核心方法
/**
 * 构造方法
 */
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.");
    }
    setRequest(request);
    setResponse(response);
}

/**
 * 创建上下文实例
 */
@Override
protected SubjectContext newSubjectContextInstance() {
    return new DefaultWebSubjectContext();
}

/**
 * 创建WebSubject实例
 */
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;
}

WebDelegatingSubject

简介

WebSubject的默认实现,保证在Request执行过程中可以保留Servlet Request/Response,供Shiro内部组件使用;

核心方法

// 请求
private final ServletRequest servletRequest;
// 响应
private final ServletResponse servletResponse;

/**
 * 构造方法
 */
public WebDelegatingSubject(PrincipalCollection principals, boolean authenticated,
                            String host, Session session, boolean sessionEnabled,
                            ServletRequest request, ServletResponse response,
                            SecurityManager securityManager) {
    super(principals, authenticated, host, session, sessionEnabled, securityManager);
    this.servletRequest = request;
    this.servletResponse = response;
}

/**
 * 是否允许创建会话
 */
@Override
protected boolean isSessionCreationEnabled() {
    boolean enabled = super.isSessionCreationEnabled();
    return enabled && WebUtils._isSessionCreationEnabled(this);
}

/**
 * 创建session上下文
 */
@Override
protected SessionContext createSessionContext() {
    WebSessionContext wsc = new DefaultWebSessionContext();
    String host = getHost();
    if (StringUtils.hasText(host)) {
        wsc.setHost(host);
    }
    wsc.setServletRequest(this.servletRequest);
    wsc.setServletResponse(this.servletResponse);
    return wsc;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值