有状态登录
在以前的单一系统中,记录用户的登录状态常使用的是有状态登录,即服务器端在用户登陆后将用户的信息保存在服务器中,从而识别用户身份。典型的做法是将用户信息存储在Session中,并分配一个SessionID存储在客户端的cookie中,当用户再次访问时,就可以通过SessionID识别用户。
但是在大型的分布式系统当中,这种做法已经无法适应时代的潮流,弊端主要有二:
一是大量的用户Session信息存储在服务器端,会对服务器产生压力。
二是由于在分布式系统当中,用户每次请求的可能不是同一台服务器,这就造成了存储在A服务器Session中的用户信息,在B服务器中无法识别。
因此,就需要使用无状态登录来解决问题。
无状态登录
无状态登录,就是服务器端不保存用户信息,服务器在通过对用户的认证之后,返回一个身份凭证(token)给客户端,用户再次请求时只需要携带token,就可以访问任意一台服务器,这样既不会对服务器端产生压力,又解决了单点登录问题。
上图在发送一个用户登录请求之后,通过解析域名将请求发送到nginx服务器,nginx服务器将请求转发到gateway网关,再经过zuul的前缀/api和/auth将请求转发到auth微服务,请求login方法,在username和password校验通过后,生成一个token存储到cookie中。
但是这里遇到一个小问题,那就是cookie中有一个域的概念,叫domain
domain:可以访问该Cookie的域名。如果设置为“.google.com”,则所有以“google.com”结尾的域名都可以访问该Cookie。注意第一个字符必须为“.”。
原本我的请求是api.leyou.com,domain应该是leyou.com才对,但是我的domain确是0.0.1,这是因为nginx在监听到了api.leyou.com之后,将请求转发到了192.168.0.101的gateway,又因为是本机IP,所以serverName变成了127.0.0.1,由于domain是根据serverName获取的,所以就变成了0.0.1,解决方法是修改nginx的配置文件
加上proxy_set_header Host $host
,这样nginx在转发时就会带上原来的host,但是这样还是不行,因为在经过zuul转发时host还会被修改一次,于是需要在application.yml中增加一句代码add-host-header: true
意思是携带本身的host头信息
但是这样还不行
Zuul内部有默认的过滤器,会对请求和响应头信息进行重组,过滤掉敏感的头信息
会发现,这里会通过一个属性为
SensitiveHeaders
的属性,来获取敏感头列表,然后添加到IgnoredHeaders
中,这些头信息就会被忽略。而这个
SensitiveHeaders
的默认值就包含了set-cookie
解决方法就是在application.yml中再加一句sensitive-headers:
,然后什么都不用写,表示用空白覆盖
这时再去登录,就会发现浏览器的cookie中已经携带了domain为leyou.com的token信息了,另外,spring-cloud-netflix-zuul2.0.1.RELEASE有BUG,会导致无法修改serverName,需要换个版本。