美文网首页
session管理

session管理

作者: yunqing_71 | 来源:发表于2019-08-22 21:00 被阅读0次

    例如:密码登录和短信验证码登录都是提交表单完成的,社交账号登录是基于OAuth2协议完成的。这三种登录方式共同点就是:
    登录成功之后用户信息是放在服务器session中的。
    这几讲讲常见的session管理:
    1.session超时处理:(用户登录之后多长时间不操作,session超时做哪些处理)

    设置server.session.timeout = 10 #单位秒
    不生效
    原因是:
    然而并没有什么用,因为SpringBoot在TomcatServletWebServerFactory代码中写了这个

    1 private long getSessionTimeoutInMinutes() {
    2 Duration sessionTimeout = this.getSession().getTimeout();
    3 return this.isZeroOrLess(sessionTimeout) ? 0L : Math.max(sessionTimeout.toMinutes(), 1L);
    4 }
    把设置的时间转化成分钟和1分钟取最大值。

    在springboot2.0之后,设置session超时的方式修改为在application.yml或application.xml上面添加

    image.png

    server.servlet.session.timeout=PT1M
    PT1M 意思是设置session失效的时间是1分钟。

    扩展:Duration
    通过查看springboot源码发现setTimeouot方法,这里要求传入Duration的实例
    public void setTimeout(Duration timeout) {
    this.timeout = timeout;
    }

    而Duration是在Java8中新增的,主要用来计算日期差值,Duration是被final声明的,并且是线程安全的
    转换字符串方式,类似于 SimpleDateFormat 的格式化日期方式 
    Duration 字符串类似数字有正负之分,默认正,负以’-‘开头,紧接着’P’,下面所有字母都不区分大小写: 
    ‘D’ – 天 
    ‘H’ – 小时 
    ‘M’ – 分钟 
    ‘S’ – 秒 
    字符’T’是紧跟在时分秒之前的,每个单位都必须由数字开始,且时分秒顺序不能乱,比如:P2DT3M5S,P3D,PT3S 
    PT3M2S 等于 -PT-3M-2S
    
    最后总结一下Duration最实用的一个功能其实是 between 方法,因为有很多时候我们需要计算两个日期之间的天数或者小时数,用这个就可以很方便的进行操作。
    

    为了便于显示由于session过期引起的需要配置:

    .and()
    .sessionManagement().invalidSessionUrl("session/invalid") //session过期后跳转的URL
    .and()

    /**
    * 配置session失效后跳转的url
    * @return
    */
    @GetMapping("/session/invalid")
    @ResponseStatus(code = HttpStatus.UNAUTHORIZED)
    public SimpleResponse sessionInvalid(){
    String message = "session失效";
    return new SimpleResponse(message);
    }

    2.session并发控制:(用户在A机器上登陆后,在B机器又登录,需要把A机器的session干掉)
    .maximumSessions(1)//设置session最大并发数量
    .maxSessionsPreventsLogin(true)//设置当session到达最大数量阻止后续的登录而不是顶掉前一个
    .expiredSessionStrategy(new YunqingExpiredSessionStrategy())//设置被顶掉之后的处理

    /**

    • session被别人登录顶掉之后的处理

    */
    public class YunqingExpiredSessionStrategy implements SessionInformationExpiredStrategy {

    @Override
    public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
    
        event.getResponse().setContentType("application/json;charset=UTF-8");
        event.getResponse().getWriter().write("并发登陆");
    }
    

    }

    3.集群session管理:(默认session是都放在中间件服务器里的,比如Tomcat,例如负载均衡没做session粘连处理,A机器的登录session不会被B机器知道,请求发到B机器上后还要求登陆)


    image.png

    解决方案如上图,把session抽取出来放到一个独立的储存里,这样哪个服务器都需要到独立的存储里去拿session.

    spring-session帮助我们完成了此功能。
    下图中所示,spring session支持的独立存储session的方式。


    image.png

    spring-session存储类型,解决session集群问题,剥离出session独立存储在redis

    spring.session.store-type = redis

    这里讲一下redis存储session,因为session是一个频繁访问的,是有超时时间的,要是存在数据库还要去清理,redis本身就可以设置超时时间。所以使用redis. 因为使用spring-session管理之后,session放到redis,所以验证码的实体类需要序列化。但是验证码的图片怎么序列化?如下解决:
    /**
    * 保存校验码
    *
    * @param request
    * @param validateCode
    /
    private void save(ServletWebRequest request, T validateCode) {
    /
    *
    * 因为图片BufferedImage类型不能序列化,所以这里取到ValidateCode不管是有没有图片,都重新new一个实例,
    * 只取码和过期时间保存到session中
    */
    ValidateCode code = new ValidateCode(validateCode.getCode(), validateCode.getExpireTime());
    validateCodeRepository.save(request, code, getValidateCodeType(request));
    }

    注意这里有一个大坑:


    因为我用的springboot2.1.6版本,所以使用spring-session依赖实现session共享的时候出现了很多莫名其妙的问题,后来换成了spring-session-data-redis依赖就解决了。。。。


    4.退出
    spring security默认的退出处理<a href="/logout">退出</a>逻辑:
    1.使当前的session失效

        2.清除与当前用户相关的rememberMe-me记录
    
        3.清空当前的SecurityContext
    
        4.重定向到登录页

    相关文章

      网友评论

          本文标题:session管理

          本文链接:https://www.haomeiwen.com/subject/dqiosctx.html