博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
springsecurity 源码解读 之 RememberMeAuthenticationFilter
阅读量:6423 次
发布时间:2019-06-23

本文共 5735 字,大约阅读时间需要 19 分钟。

RememberMeAuthenticationFilter 的作用很简单,就是用于当session 过期后,系统自动通过读取cookie 让系统自动登录。

我们来看看Springsecurity的过滤器链条。

我们发现这个 RememberMeAuthenticationFilter  在 匿名构造器之前,这个是为什么呢?

还是从源码来分析:

if (SecurityContextHolder.getContext().getAuthentication() == null) {            Authentication rememberMeAuth = rememberMeServices.autoLogin(request, response);            if (rememberMeAuth != null) {

代码中有这样的一行,当SecurityContext 中 Authentication 为空时,他就会调用 rememberMeServices 自动登录。

 

因此刚刚的问题也就好解释了,因为如果RememberMeAuthenticationFilter  没有实现自动登录,那么他的Authentication 还是为空,

这是可以创建一个匿名登录,如果先创建了匿名登录,那么这个 RememberMeAuthenticationFilter   的判断就不会为null,过滤器将失效。

 

我们看看rememberMeServices 的autoLogin 登录

我们贴出实现的代码:

public final Authentication autoLogin(HttpServletRequest request, HttpServletResponse response) {        String rememberMeCookie = extractRememberMeCookie(request);        if (rememberMeCookie == null) {            return null;        }        logger.debug("Remember-me cookie detected");        if (rememberMeCookie.length() == 0) {            logger.debug("Cookie was empty");            cancelCookie(request, response);            return null;        }        UserDetails user = null;        try {            String[] cookieTokens = decodeCookie(rememberMeCookie);            user = processAutoLoginCookie(cookieTokens, request, response);            userDetailsChecker.check(user);            logger.debug("Remember-me cookie accepted");            return createSuccessfulAuthentication(request, user);        } catch (CookieTheftException cte) {            cancelCookie(request, response);            throw cte;        } catch (UsernameNotFoundException noUser) {            logger.debug("Remember-me login was valid but corresponding user not found.", noUser);        } catch (InvalidCookieException invalidCookie) {            logger.debug("Invalid remember-me cookie: " + invalidCookie.getMessage());        } catch (AccountStatusException statusInvalid) {            logger.debug("Invalid UserDetails: " + statusInvalid.getMessage());        } catch (RememberMeAuthenticationException e) {            logger.debug(e.getMessage());        }        cancelCookie(request, response);        return null;    }
extractRememberMeCookie这个方法判断 SPRING_SECURITY_REMEMBER_ME_COOKIE 这样的cookie,如果没有就直接返回了null。
processAutoLoginCookie:这个是处理cookie 并从cookie加载用户。 默认springsecurity 使用类 TokenBasedRememberMeServices 来解析 cookie。 实现代码如下:
protected UserDetails processAutoLoginCookie(String[] cookieTokens, HttpServletRequest request,            HttpServletResponse response) {        if (cookieTokens.length != 3) {            throw new InvalidCookieException("Cookie token did not contain 3" +                    " tokens, but contained '" + Arrays.asList(cookieTokens) + "'");        }        long tokenExpiryTime;        try {            tokenExpiryTime = new Long(cookieTokens[1]).longValue();        }        catch (NumberFormatException nfe) {            throw new InvalidCookieException("Cookie token[1] did not contain a valid number (contained '" +                    cookieTokens[1] + "')");        }        if (isTokenExpired(tokenExpiryTime)) {            throw new InvalidCookieException("Cookie token[1] has expired (expired on '"                    + new Date(tokenExpiryTime) + "'; current time is '" + new Date() + "')");        }        // Check the user exists.        // Defer lookup until after expiry time checked, to possibly avoid expensive database call.        UserDetails userDetails = getUserDetailsService().loadUserByUsername(cookieTokens[0]);        // Check signature of token matches remaining details.        // Must do this after user lookup, as we need the DAO-derived password.        // If efficiency was a major issue, just add in a UserCache implementation,        // but recall that this method is usually only called once per HttpSession - if the token is valid,        // it will cause SecurityContextHolder population, whilst if invalid, will cause the cookie to be cancelled.        String expectedTokenSignature = makeTokenSignature(tokenExpiryTime, userDetails.getUsername(),                userDetails.getPassword());        if (!equals(expectedTokenSignature,cookieTokens[2])) {            throw new InvalidCookieException("Cookie token[2] contained signature '" + cookieTokens[2]                                                                                                    + "' but expected '" + expectedTokenSignature + "'");        }        return userDetails;    }   
protected String makeTokenSignature(long tokenExpiryTime, String username, String password) {        String data = username + ":" + tokenExpiryTime + ":" + password + ":" + getKey();        MessageDigest digest;        try {            digest = MessageDigest.getInstance("MD5");        } catch (NoSuchAlgorithmException e) {            throw new IllegalStateException("No MD5 algorithm available!");        }        return new String(Hex.encode(digest.digest(data.getBytes())));    }

 

这个代码就是加载用户,并验证cookie 是否有效。

因此我们在写入cookie 时,产生的cookie 过程如下:

String enPassword=EncryptUtil.hexToBase64(password);                long tokenValiditySeconds = 1209600; // 14 days        long tokenExpiryTime = System.currentTimeMillis() + (tokenValiditySeconds * 1000);        String signatureValue = makeTokenSignature(tokenExpiryTime,username,enPassword);        String tokenValue = username + ":" + tokenExpiryTime + ":" + signatureValue;        String tokenValueBase64 = new String(Base64.encodeBase64(tokenValue.getBytes()));                        CookieUtil.addCookie(TokenBasedRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY,                 tokenValueBase64,60 * 60 * 24 * 365, true, request, response);

 

 
 

 

转载于:https://www.cnblogs.com/yg_zhang/p/10659490.html

你可能感兴趣的文章
数据库性能优化之冗余字段的作用
查看>>
DBA_实践指南系列9_Oracle Erp R12应用补丁AutoPatch/AutoControl/AutoConfig(案例)
查看>>
数据库设计三大范式
查看>>
ionic 字体的导入方法
查看>>
IP路由原理
查看>>
内部类详解
查看>>
洛谷P2726 阶乘 Factorials 数学
查看>>
类加载机制
查看>>
火柴棒等式(2008年NOIP全国联赛提高组)
查看>>
mongodb int型id 自增
查看>>
【转】关于大型网站技术演进的思考(十八)--网站静态化处理—反向代理(10)...
查看>>
Java中的4种代码块
查看>>
Ocelot(七)- 入门
查看>>
生成水杯热气
查看>>
程序员工作心法
查看>>
三个常用的PHP图表类库
查看>>
python中异常处理--raise的使用
查看>>
高中数学与初中数学的接轨点
查看>>
python 安装第三方模块
查看>>
Whitelabel Error Page 专题
查看>>