学习资源来源于:SpringBoot2.0前后端分离开发之用户身份认证实战 (后端实现)--Java视频教程-后端开发-CSDN程序员研修院
自说自话:session即会话,因为浏览器访问服务是无状态的,为了保证用户可以登入后正常访问服务,所有才有了session,平时springboot项目的session是服务端(springhttpsession?)控制生成和销毁的,可以直接从请求中获取当前请求的session,这时session只存在于服务器端,怎样判断请求是不是这次会话的呢?答案是容器会根据session生成sessionId并将这个ID返回给浏览器,浏览器会根据访问的url+返回的sessionId生成一个cookie信息,浏览器在下次再访问这个路径的信息时会自动将这个cookie信息携带上,容器会自动获取请求中的cookie(sessionId)来判断是否是同一个会话,或者判断当前会话的用户是否登入过;
那为什么需要session共享呢?
在集群中有很多个相同的实例服务,因为session是只存在于每个服务器中,假设用户登入请求发送到了服务器A,此时A中session中有该用户的用户信息,但下次请求请求到了服务器B,B服务中没有该用户的用户信息,则又会被提示重新登入,所有才会有session共享的问题,即登入一次之后不管下次请求请求到了那一台服务器上都会获取到该用户的登入信息;
那session共享有哪些方式可以实现呢?
先说结论:
1、token/jwt+数据库/缓存中间件
2、session(+shiro)+数据库/缓存中间件
token+数据库(半有状态)
1、token访问流程
常见的一些问题
2、生成token+保存(数据库/缓存)
(1)、token可以使用用户名、密码、时间戳、随机字符串(雪花算法字符串)等信息来生成;要保证足够复杂、神秘并要保证解析足够块;
(2)、根据以上信息生成一个json字符串并对其进行AES加密,可以自定义一个工具来进行加解密(AES加密可以百度一下)
3、验证
(1)对于多次/多客户端登入的情况,看是否需要对之前的token无效-为了系统的安全性(登入操作时校验)
(2)AOP中拦截需要受保护资源的请求并验证token;
1>、超时的token要及时无效
2>、防止token的伪造需要解析token并验证token的正确性
3>、登入时间、超时时间不要存放在数据库中,因为可以人为修改,可以放到实体类中,加密到token中,在解析出token后根据解析出来的信息来校验过期时间等(当然可以放到数据库中只不过只是一个参考时间实际的判断逻辑是根据解析出来的数据做的校验)
(3)定时清理/转移存储中的无效token,避免资源浪费;
(4)修改密码设置token无效并提示重新登入;
(5)重新登入、退出登入要设置token无效;
(6)刷新token过期时间或者设置token时间相对长一点
4、缺点
使用关系型数据库存储token有效率问题,不推荐使用;
5、解决方案
使用缓存数据库,不但效率高还可以实现集群服务的session共享问题;
(1)登入后将token存入缓存;每次登入都存入,但缓存数据库中只会有一条数据,并且可以自动超时;
------------------------访问接口验证↓--------------------
(2)验证token是否为伪造数据;
(3)判断缓存中是否存在该key的值
(4)传入的token和查询的token必须完全一致;
(5)修改密码要记得删除缓存中的token(和退出登入一样需要重新登入);
jwt(token)(无状态)
jwt : json web token,通过jwt+算法(rsa、sha256等),加密方式为对称加密;
无状态的(服务端不存储token信息),客户端通讯中的token信息会带有自我描述,来验证身份;jwt生成的token更加的安全;
1、添加jwt依赖(参照图1)
2、使用jwt生成token(参照图2),(id可以使用用户id,主体可以使用用户名)
3、验证token(采用jwt组件提供的api进行验证就可以了)(参照图3)
4、缺点:jwt不提供无效、注销token,因为服务端不存储,只是登入成功后生成的一个字符串给客户端,过期时间是生成token是确定的,也不存在在客户端删除,只能等过期时间到了才会自动失效;所有...
5、解决方案:
1>可以和前端协商好,当修改密码或者退出登入后清楚token;但并不是万全之策;
2>结合redis加以辅助,可以让redis控制过期时间和注销;
总结:
不建议直接使用token用于集群模式下的session共享,
可以用于第三方服务调用的授权;或者单点登入的授权;(即这些服务不需要注销token)
jwt+redis(半有状态)
由redis来控制过期时间;
1、修改生成token时过期时间的设置
2、登入时使用jwt创建token并存入缓存,并设置缓存时间;
3、使用jwt验证token的合法性并判断缓存中的token是否和传入的完全相同;
4、修改密码、退出登入需要删除缓存中的token;
总结:jwt完成了很大一部分工作(token生成、验证、解析,主要保证信息的安全性),redis核心就是解决过期时间;可以应用于实际的业务场景中;
token-jwt-图
图1
图2
图3
session(完全有状态)
1、session的访问流程(图中没有讲到cookie)
2、使用spring家族的服务时,每个请求都可以将HttpSession、httpServletRequest、httpServletResponse等注入到请求参数中;所以session的创建是由spring来创建的;
3、可以直接对当前请求的session设置过期时间;此时的过期为动态的,是没有任何操作时的过期时间,如果在过期时间内有其他操作会刷新过期时间;
4、登入成功后会在浏览器或者postman中的cookie中生成该路径所对应的一个cookie值;(可以将sessionId作为key放到session中,下次直接根据当前session的id来获取信息)
5、验证session,在session中获取登入时设置的值,如果获取的值没有问题则表示已经登入,否则表示没有登入;
6、修改密码、退出登入主要注销掉session并提示重新登入;(参照图1)
图1
session+redis
1、添加依赖,修改配置文件(参照图1)
配置文件中声明的含义是将session存放于哪个位置;redis;(spirng整合的组件)
问题:直接添加依赖+配置文件就可以了吗?在服务器端获取的session是在redis中获取的吗?
退出登入或者修改密码时注销session会注销掉redis中的数据吗?
图1:yml配置文件添加
shiro(有状态) todo:对shiro不是很熟悉,需要专题来学习
权限认证安全框架
shiro中的session接替了spring session中的httpsession
1、添加依赖(参照图1)
2、使用shiro登入(参照图2)
图1
分布式调用,不用的话可以不添加
图2
shiro+redis(推荐使用)
1、添加依赖(参照图1)
2、修改shiroConfig配置文件,配置redis相关
注:
1、退出登入后redis中的session会被清楚掉,此时如果再访问服务这时是访问失败的,但redis中会生成一个新的sessionId,这个sessionId为下次登入是值;(会默认生成一个值)
2、shiro和httpsession一样都会在浏览器端保存有sessionId;通过此id进行的通讯和redis缓存;
3、超时时间会被刷新
图1
-------------------------------------------------------------------------------------------------------------------------
涉及功能:登入、登出、修改密码、请求校验
注:、
1、cookie对应的sessionId;
2、浏览器关闭后则session会话结束;
3、服务器保存session默认30分钟;
4、使用Nginx中的ip绑定策略,同一个ip只能在指定的同一个机器访问(不支持负载均衡,这种方式跟sesson共享没有关系)
5、cookie有效时间是一个会话,如果关闭浏览器则会话失效,cookie会被浏览器删掉;
6、服务器重启后session被释放掉,浏览器拿着之前的sessionId(cookie)来获取session中信息时,是获取不到的了,已经消失;
问题:
1、浏览器访问服务,此时服务根据每次访问会生成新的session吗?如果带有cookie访问会讲该cookie对应的session注入到当前请求中吗?
:web端的会话是靠sessionId来维持的,如果第一次访问服务时,服务器返回信息中在header中设置了cookie信息,即将sessionId给浏览器设置,则下次再访问服务器时,web服务器可以获取到该cookie对应的session,如果没有带有cookie或者session失效则会生成新的session;
2、自动登入是怎么的呢?浏览器中保留了账号密码吗?