后端开发之多应用之间单点登录

后端开发之多应用之间单点登录_第1张图片        

        早上还没到公司,电话就响了,电话那头一个妹子的声音,我一听,咦!第一感觉系统有问题,然后还没等某人开口,我就问系统啥问题???她说你别慌,我就让你赶紧到公司帮我刷个数据而已啊,难道你们程序员脑子都是bug吗?我系统用户名密码忘记了,帮我重置下,公司系统太多了,都要记,我是一个文科生哎!难为我,能不能只让我登录一次系统其他系统我点点点直接跳转进去行不行。。。真想自己去改bug。行了不说了,你赶紧的。。。。

 

后端开发之多应用之间单点登录_第2张图片

 

 

 

01

 

 

没有应用场景的技术讨论都是耍流氓

 

 

       当我们学习一门新技术时,目的是为了提高自己的能力呢?还是去解决某一个场景问题或是系统Bug。学习技术肯定是需要将技术应用到系统开发,如果系统运营良好,这样技术的价值才得以体现。如果花费了大量时间和精力学习很多技术,但是这些技术并没有用到,这样你的技术价值也没有输出体现。更具体一点比喻就是,你搬了一大堆的砖,但是你并没有用这些砖去建筑成一个房子,那砖的意义价值不大,只是满足你个人的虚荣心,或者就是一种瞎忙。

        大家对商品秒杀应该都比较熟悉,用技术去解决这种场景就有很大的价值

秒杀业务,是典型的短时大量突发访问类问题。具体是用什么技术去解决这种问题呢?大多数人会说Redis和消息队列,可是有时候我们这两种技术不是很熟悉,那怎么办呢?作为一个程序员来说肯定是死磕到底了。

        针对场景的不同,使用的技术和方式也不同,是好读书不求甚解,还是字字斟酌,还是囫囵吞枣了解是什么,后面用到再

细看,这些都是看情况而定。

 

 

 

02

如何理解单点登录

 

 

  一、http请求无状态请求

 

        传统的web开发,有web应用、服务器和客户端。用户使用浏览器发送一个http请求给web服务器,稍微有点web经验的人都知道,http请求是一种无状态的请求。我们在实际业务中开发或多或少要知道这个请求是谁发送过来的,又因为传统的http是无状态的,假设是同一个客户端,下一次又发送一个http请求,那么这两次请求,都是新的请求,就不知道到底是谁发送的。

 

二、Session机制

 

       我们传统的web服务器采用的是一种叫Session机制来确定这个请求是不是同一个用户发送过来的。浏览器第一次请求服务器,服务器创建一个会话,并将会话的id作为响应的一部分发送给浏览器,浏览器存储会话id,并在后续第二次和第三次请求中带上会话id,服务器取得请求中的会话id就知道是不是同一个用户了。当客户端发送http请求访问tomcat服务器时,浏览器中可以看到一个名为“JSESSIONID”的cookie,这就是tomcat会话机制维护的会话id,因业务需要我们可能会存储一些其他信息如userId,来确保用户的标识,发送的是不是同一个人。

 

后端开发之多应用之间单点登录_第3张图片

 

三、集群和分布式下面有什么问题

 

        如部署两台服务器,中间通过nginx做负载均衡代理,我们请求都通过nginx分发到不同的web服务上面去。我们还是采用传统的session方式来架构的话,如用户第一次login被代理到web1,web1上面会有用户信息

第二次调用一个getuser操作,如果这个操作被代理到web2上面去,那用户获取的数据将是为空的。除非在web2重新登录一次,并保存session信息。这样做法比较麻烦,请求不同的web服务器都要先判断用户是不是存在,不存在重新登录获取用户信息。我们把解决这种问题的方式叫做单点登录。

后端开发之多应用之间单点登录_第4张图片

 

 

03

单点登录解决方案

 

1、简单方案


        通过客户端请求ip进行hash,再通过hash值选择后端server。

        ip_hash能够将某个ip的请求定向到同一台后端web机器中,这样一来这个ip 下的客户端和某个后端 web机器就能建立起稳固的session.

ip_hash机制能够让某一客户机在相当长的一段时间内只访问固定的后端的某台真实的web服务器,这样会话就会得以保持,在网站页面进行login的时候就不会在后面的web服务器之间跳来跳去了,也不会出现登录一次的网站又提醒重新登录的情况.

后端开发之多应用之间单点登录_第5张图片

        这种方式可以实现我们单点登录,但是这种方式有几个缺陷。

1、ip不能变  2、单点故障 。在分布式环境下,难免会出现宕机情况。

如果web1宕机了,上面的用户信息将全部丢失,这个非常致命的,每台web服务都是各自存的用户信息,他们之间是不知道对方存了多少用户信息。如果系统比较小,对用户信息不怎么敏感的话,丢失就丢失了。让用户重新登录就好了,如果是这样的一个系统可以采用这个方式。

       有朋友说可以使用tomcat session复制来解决用户丢失的问题啊,不错是可以解决这个问题,不过当用户数据量非常大的时候,每台服务上面都要保持完整的用户信息。这对服务器负载会造成很大影响,还有一点由于网络延迟问题,可能同步比较慢,有时候也取不到用户信息。

后端开发之多应用之间单点登录_第6张图片

        这种方式只适合集群环境的单点登录,如果两个应用在不同环境下部署,那这个方案就解决不了单点登录问题。

 

 

2、成熟方案

 

       大家平时上电商网站比较多,比如经常逛的淘宝和天猫,他们两个系统之家有个角色叫user,当用户发送一个登陆请求到淘宝服务器,淘宝服务器登录完成后,可把用户信息存入第三方存储(store)介质里面去如用redis存储用户信息,当我们用户第二次登录天猫的时候,从第三方介质(redis)里面去获取登录信息。

       理论上看起来这个思路没有问题,当具体实现的时候,有一个细节上的问题。用户登录之后,淘宝往store保存用户信息,存储的内容肯定是一个Map的数据结构,那么问题来了,Map里面Key是什么呢?以及他们之间是如何通讯呢?

       对于Key的话,只要是一个唯一标识就可以了,通常做法是用户登录完成后我们会在后端默认创建一个Session信息,这个Session不是tomcat和浏览器Session,是我们存储在数据库的数据,标识了当前用户登录信息,我们可以把Session uuid作为Map的Key来存储到第三方存储介质里面去。

       那么问题来了,天猫怎么知道淘宝存的uuid是什么?其实前面我们没有说全,淘宝登录成功后除了把登录信息保存到第三方存储介质,还要给客户端返回一个uuid,客户端拿到这个uuid之后可以把他存在本地缓存中如localstorage、sessionstorage、cookie等,如果客户端是手机,可以存到一个临时文件中。这样下次我客户端在请求天猫的时候,从本地缓存获取到uuid,然后带过去,去从三方存储介质获取登录信息。

        好了这时候有人会问,那有没有跨域问题吗?这种情况肯定有,但是可以解决,后端程序可以设置相应的域名如springboot做法就是定义一个

import org.springframework.context.annotation.Configuration;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter(filterName = "CorsFilter ")
@Configuration
public class CorsFilter implements Filter {
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin","*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
        chain.doFilter(req, res);
    }
}

         目前互联网都是微服务架构,中间肯定会有一层网关,来代理我们其他的服务,跨域问题就不存在了。这种是目前一线互联网常用的解决方案。这种侵入性和耦合性比较低。我们说到现在大家有没有发现还有一个问题就是,如何保证多个服务之间用户信息的传递呢,其实很简单,每次请求各个服务及子系统的时候,在request header信息里面带入uuid,每次系统访问的时候,从header拿出uuid然后到三方存储介质获取登录信息,这个操作客户封装成统一的方法无操作,如利用拦截器等方法。

后端开发之多应用之间单点登录_第7张图片

          

 

 

04

总结一下

 

       单点登录在现在的系统架构中广泛存在,他将多个子系统的认证体系打通,实现了一个入口多处使用,而在架构单点登录时,也会遇到一些小问题,在不同的应用环境中可以采用不同的单点登录实现方案来满足需求。

        最后用一个郭德纲常用的开场白 “单丝不成线,孤木不成林。人浑身是铁能捻几根钉子?要不是于谦我早红了”。应用于今天的多系统集成倒是十分恰当。

 

欢迎添加个人微信号:xijieeren

你可能感兴趣的:(Java)