赞
踩
简单概括就是,对于一个系统有多个应用(淘宝有淘宝,天猫)的情况,用户只需登陆一次,就可以访问所有该系统下的其它应用(登录了淘宝后,跳转到天猫也不用登陆了)。
首先要知道,登录的目的是为了访问某些受保护资源,或执行一些特殊权限。
网站传输的是http协议,而http协议是无状态的,即只通过http连接无法判断用户的登录状态的。举个例子:用户在登录页面进行登录("/login")之后跳转到主页("/index"),而主页又是一个新的http连接,此时主页已经不知道用户是否登录了,所以如果执行某些操作时仍需要获取用户的账号,密码等信息。我们当然可以通过url携带参数的模式传递信息,进行验证,但是这个方式对于用户太不友好了。目前的解决方案是:引入Cookie,Session机制。
网站可以通过cookie,session机制来存储用户的登陆状态。
cookie是存储在客户端(用户的浏览器)的,当用户访问网站进行登录后,网站就会给当前用户颁发一个Cookie,在该Cookie有效期内,用户再次访问这个网站时,服务器会验证当前Cookie是否合法,从而减少了用户重新登陆的可能性。
session则是一个概念,或者说是一种机制,之所以要跟cookie一起讨论是因为,一般session机制的实现都是在cookie中存储一个 k-v结构的JSEESIONID。你可以F12查看一下,大多数网站都有。可以理解为,用户建立连接->发送cookie->服务端验证 这个过程,称之为session会话。用户在第一次登陆后,服务器端就会为该用户创建一个session,并分配一个独一无二的JSESSIONID,将JSESSIONID以cookie形式传给浏览器。
当然并非只有这一种解决http无状态的方案,而且cookie session机制同样有许多缺点,而单点登录就是基于其中一个缺点而出现的。
最基础的cookie-session机制只能解决单体服务的登录模式,而现在的大部分的服务系统都是多系统模式,如CSDN的主页是:www.csdn.net,而个人信息页是:www.blog.csdn.net,学过计算机网络的同学应该可以看出来,两者的域名是个父子关系。这种情况下,依然用不上单点登录,我们可以通过设置cookie的作用域(domain)来解决问题。如:把所有*.csdn.net的作用域全都设置为csdn.net,这样,所有csdn.net的子域名都可以获取到这个cookie。但这是对于存在父子关系的服务情况,而另外的一个情况:淘宝的域名是:taobao.com,而天猫的域名是:tmall.com。但是这两者都属于淘宝的业务,而如果我们要实现的就是在淘宝上登录之后,天猫就也自动登录的效果,就无法使用之前的方案了,因为这两者的域名,没有任何关系。至此,引出了单点登录。
单点登录(SSO):
既然已经知道了问题所在,那么我们解决的思路是什么呢?
建立一个所有系统公共的登录认证中心(sso-server),用户在访问任意一个子系统受保护资源时都需要去sso-server去认证。
首次访问A->A发现用户没登陆->跳转到sso-server认证->认证失败->引导至登陆页面->用户输入账号密码进行登录->sso-server校验账号密码->授权令牌->返回到子系统页面->拿到令牌再去sso-server认证->认证成功->登录成功。
此时,sso-server与该子系统之间维护了一个局部会话,sso-server与用户之间维护了一个全局会话。
用户访问其它系统B,B发现用户没登录->跳转到sso-server->sso-server认证成功,返回令牌->B拿到令牌,再去sso-server校验->校验通过,允许访问受保护资源。
此时,sso-server与B系统也维护了一个全局会话。
允许我偷个图:
我们至少需要启动两个server,一个作为子系统,一个作为sso-server,才能体现出单点登录。
我们需要一个拦截器,在访问子系统受保护资源时进行拦截,判断登陆状态,是否跳转到认证中心。
前端页面:随便写写,主要是我也不会。
用户访问主页面过程:
首先启动sso-server服务(8080端口)作为认证中心,再启动demo服务(8082端口)作为子系统。
访问localhost:8082:/,也可以自己写俩域名,不重要。
拦截器启动,拦截"/"请求,判断登录状态。
首先,尝试获取本地Session中的accesstoken,若该token存在,说明最近登陆过,直接放行;否则,尝试获取授权码code,若授权码存在,说明认证中心最近被登陆过,可以通过code来生成一个自己的accesstoken,然后放行;若两者都不存在,说明是第一次访问,重定向到sso-server的登录("/login")页面(记住携带参数,方便我们登录认证完成后回到demo的index页面)。
到了sso-server的login页面后,输入账号密码,做一个简单的校验(没使用数据库,项目重点不在这),点击登录,校验成功后,尝试从浏览器中获取cookie,如果不存在则创建一个并存入浏览器中。接着创建授权码code,并将授权码存入本地变量(可以设置一个过期时间)。然后令url携带授权码信息,重定向回原来的页面(即demo的index)。
回到index后又触发拦截器,同样判断accesstoken与code,此时前者仍为null,但后者已经创建成功被添加在url上;因此我们需要通过code码来获取一个accesstoken,这里使用Oauth2协议,所以url中会添加oauth参数,整体格式如下:
接着模拟一个http请求, 将paramMap中所有参数拼接到url上,并访问这个url。
得到的result是一个json格式数据,解析该数据,并将重要参数存储到本地,然后使用这些参数(约定好的appid和appsecret),来生成一个本地token,同时记录本地session和token的映射。
最后,为了回到原来的地址(现在的地址包含了各种授权码参数等),再做一次重定向,重定向并渲染元素到demo的index页面。至此,访问成功。
访问sso-server的index,模拟单点登录
直接输入8080:/,被拦截器拦截,尝试获取accesstoken和code,都获取失败(因为是其他网页的请求),接着被重定向到sso-sever的login页面,
但是!重点!
因为上次demo登录已经生成了cookie并存储在本地!所以直接验证cookie即可,不需要再输入账号密码登录,用户看不到登录页面!
直接去创建code和accesstoken,步骤跟demo的基本一致。最终实现,单点登录
之后在服务开启的情况下随便刷新页面,都会在判断accesstoken时直接放行通过。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。