spring security 5 session管理

spring security 如何保存我们的登录信息。


根据官方文档我们可以知道通过登录验证(AuthenticationProvider.authenticate(Authentication authentication)方法中验证,返回一个Authentication->UsernamePasswordAuthenticationToken(userDetails, password, authorities);)后,会将一个验证通过的实例Authentication放入安全上下文SecurityContextSecurityContext可从SecurityContextHolder中获得。
Authentication信息包括:

  • principal -验证用户,通常为UserDetails实例(实际生产中实现该接口,通过数据库查询该信息)。
  • credentials -通常是密码。在许多情况下,将在验证用户身份后清除此内容,以确保它不会泄漏。
  • authorities -权限GrantedAuthority。 通常是角色或范围。

验证通过后,后续需要登录用户信息可直接从Authentication获取。

spring security 如何记录登录状态

我们知道javaweb 通过jsession 会话id来确保同一个会话,同一个连接。在security中同样通过jSessionId来记录用户登录,每次请求到达服务端,会通过ConcurrentSessionFilter过滤器验证是否存在该session,不存在则不是登录状态。验证通过继续执行FilterChain后续的过滤器。
ConcurrentSessionFilter部分源码

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)req;
        HttpServletResponse response = (HttpServletResponse)res;
        HttpSession session = request.getSession(false);
        if (session != null) {
            SessionInformation info = this.sessionRegistry.getSessionInformation(session.getId());
            if (info != null) {
                //session过期做退出登录处理
                if (info.isExpired()) {
                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Requested session ID " + request.getRequestedSessionId() + " has expired.");
                    }

                    this.doLogout(request, response);
                    this.sessionInformationExpiredStrategy.onExpiredSessionDetected(new SessionInformationExpiredEvent(info, request, response));
                    return;
                }
                //若该session存在,则刷新它的最后请求时间
                this.sessionRegistry.refreshLastRequest(info.getSessionId());
            }
        }
        //若该session不存在,后续处理中会做未登录处理
        chain.doFilter(request, response);
    }

SessionManagementFilter部分源码

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)req;
        HttpServletResponse response = (HttpServletResponse)res;
        //判断是否被该过滤器处理过
        if (request.getAttribute("__spring_security_session_mgmt_filter_applied") != null) {
            chain.doFilter(request, response);
        } else {
            request.setAttribute("__spring_security_session_mgmt_filter_applied", Boolean.TRUE);
            if (!this.securityContextRepository.containsContext(request)) {
                Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
                if (authentication != null && !this.trustResolver.isAnonymous(authentication)) {
                    try {
                        this.sessionAuthenticationStrategy.onAuthentication(authentication, request, response);
                    } catch (SessionAuthenticationException var8) {
                        this.logger.debug("SessionAuthenticationStrategy rejected the authentication object", var8);
                        SecurityContextHolder.clearContext();
                        this.failureHandler.onAuthenticationFailure(request, response, var8);
                        return;
                    }

                    this.securityContextRepository.saveContext(SecurityContextHolder.getContext(), request, response);
                } else if (request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid()) {
                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Requested session ID " + request.getRequestedSessionId() + " is invalid.");
                    }

                    if (this.invalidSessionStrategy != null) {
                        this.invalidSessionStrategy.onInvalidSessionDetected(request, response);
                        return;
                    }
                }
            }

            chain.doFilter(request, response);
        }
    }
退出登录或删除cookie后的请求security如何处理
  • 请求中未携带 jSessionId时只能请求公共资源,无法访问私有资源。(security 定义)
    WebSecurityConfigurerAdapter继承类中定义
@Override
	public void configure(WebSecurity web) throws Exception {
                //指定多个公共资源,无需登录即可访问
		web.ignoring().antMatchers("/login.html", "/page/login/**");
	}
  • 退出登录后的请求会继续验证session是否存在,不存在则重新登录。
posted @ 2020-12-17 11:16  复一日  阅读(454)  评论(0编辑  收藏  举报