zoukankan      html  css  js  c++  java
  • Nodejs----单点登录

    ---------------------------------------------------------------------------------------------单点登陆原理-----------------------------------------------------------------------------------------------------------------------------
    
    	1:http无状态协议:
    		web采用客户端-服务端架构,http做为通信协议,浏览器的每一次请求,服务器会独自处理,
    		不与之间之后的请求产生关联。
    		三次请求/响应之间没有任何关系:
    			浏览器	                 客户端
    				------------------------
    			   |						| 
    			   -------第(1)次请求-------->
    			   |						|
    			   <------第(1)次响应--------
    			   |						|		
    			   |						|
    			   |						|
    			   -------第(2)次请求-------->
    			   |						|
    			   <------第(3)次响应---------
    			   |						|
    			   |						|
    			   |						|
    			   -------第(2)次请求-------->
    			   |						|
    			   <------第(3)次响应---------
    			   |						|
    			   |						|
    				------------------------
    			但这也同时意味着,任何用户都能通过浏览器访问服务器资源,如果想保护服务器的某些资源,
    			必须限制浏览器请求;要限制浏览器请求,必须鉴别浏览器请求,响应合法请求,忽略非法请求;
    			要鉴别浏览器请求,必须清楚浏览器请求状态。
    			既然http协议无状态,那就让服务器和浏览器共同维护一个状态吧!这就是会话机制
    			  
    	2: 会话机制:
    		浏览器第一次请求服务器,服务器创建一个会话,并将会话的id作为响应的一部分发送给浏览器,
    		浏览器存储会话id,并在后续第二次和第三次请求中带上会话id,
    		服务器取得请求中的会话id就知道是不是同一个用户了,这个过程用下图说明,后续请求与第一次请求产生了关联:
    		
    			浏览器	                 客户端
    				------------------------
    			   |						| 
    			   -------第(1)次请求-------->---------------[创建会话]
    			   |						|                         |
    			   |                        |<------------------------|
    			   |                        |
    			   |                        |
    			   <------第(1)次响应------------->(会话id)
    			   |                        |
    			   |-------------|			|		
    			   | 保存会话(id)|          |
      			   |     <-------|          |
    			   |						|
    			   -------第(2)次请求-------------->(会话id)
    			   |						|
    			   <------第(3)次响应---------
    			   |						|
    			   |						|
    			   |						|
    			   -------第(2)次请求--------------->(会话id)
    			   |						|
    			   <------第(3)次响应---------
    			   |						|
    			   |						|
    				------------------------
    			
    			服务端在内存中保存会话对象,浏览器怎么保存会话id:
    				请求参数:
    					将会话id作为一个请求参数,服务器接收请求自然能解析参数获得会话信息,并借此来判断是否来自同一
    					会话,很明显,这种方式不靠谱。
    				cookie:
    					那就浏览器自己来维护这个会话id,每次发送http请求时浏览器自动发送
    					会话id,cookie机制正好可以来处理这件事。cookie时浏览器用来存储少量
    					数据的一种机制,数据以Key:value的形式存储,浏览器请求时自动附带cookie信息。
    					
    			tomcat会话机制当然也实现了cookie,访问tomcat服务器时,
    				浏览器中可以看到一个名为“JSESSIONID”的cookie,这就是tomcat会话机制维护的会话id.
    				
    				浏览器	                 客户端
    					------------------------------
    				   |						       | 
    				   -------第(1)次请求--------------->---------------[创建会话]
    				   |						       |                         |
    				   |                               |<------------------------|
    				   |                               |
    				   |                               |
    				   <------第(1)次响应---------------(cookie:JSsessionid)
    				   |                               |
    				   |----------------------|		   |		
    				   | 设置cookie(jssessionid)       |
    				   |     <----------------|        |
    				   |						       |
    				   -------第(2)次请求--------------->(cookie:JSsessionid)
    				   |						       |
    				   <------第(3)次响应---------------
    				   |						       |
    				   |						       |
    				   |						       |
    				   -------第(2)次请求-------------->(cookie:JSsessionid)
    				   |						       |
    				   <------第(3)次响应---------------
    				   |						       |
    				   |						       |
    					-------------------------------
    
    	3: 单点登录:
    		什么是单点登录:
    			单点登录全称Single Sign On(以下简称SSO),
    			是指在多系统应用群中登录一个系统,便可在其他所有系统中得到授权而无需再次登录,
    			包括单点登录与单点注销两部分
    			
    		登录:
    			相比于单系统登录,sso需要一个独立的认证中心,
    			只有认证中心能接受用户的用户名密码等安全信息,
    			其他系统不提供登录入口,只接受认证中心的间接授权。
    			间接授权通过令牌实现,sso认证中心验证用户的用户名密码没问题,创建授权令牌,
    			在接下来的跳转过程中,授权令牌作为参数发送给各个子系统,子系统拿到令牌,即得到了授权,
    			可以借此创建局部会话,局部会话登录方式与单系统的登录方式相同。
    			
    			图示:
    						浏览器             系统1               系统2          sso认证中心 
    						   *-----------------*--------------------*-----------------*-
    						   |                 |                    |                 |
    						   |                 |                    |                 |
    						   |                 |                    |                 |
    						   ---访问(系统1)------>                  |				    |
    						   |                 |                    |                 |
    						   |                 |-----------------   |                 |
    						   |                 |                |   |                 |
    						   |                 <----验证未登陆---   |                 |
    						   |                 |                    |                 |
    						   |                 |                    |                 |
    						   |                 |----------跳转(系统1的地址)------------>
    						   |                 |                    |                 |------------------
    						   |                 |                    |                 |                 |
    						   |                 |                    |                 <----验证未登陆-----
    						   |                 |                    |                 |
    						  <-----------登陆页面(系统1的地址)--------------------------
    						   |                                      |                 |
    						   ------------登陆(usrname,password,系统1的地址)----------->
    						   |                  |                    |                |-------------------
    						   |                  |                    |                |                  |
    						   |                  |                    |               <---验证成功---------
    						   |                  |                    |                |
    						   |                  |                    |                |-------------------
    						   |                  |                    |                |                  |
    						   |                  |                    |               <---创建全局会话-----
    						   |                  |                    |                |
    						   |                  |                    |                |-------------------
    						   |                  |                    |                |                  |
    						   |                  |                    |               <---创建授权令牌-----
    						   |                 <----------跳转(令牌)-------------------
    						   |                  |                    |                |
    						   |                  |                    |                |
    						   |                  -----------校验(令牌)------------------>
    						   |                  |                    |                |
    						   |                  |                    |                |-------------------
    						   |                  |                    |                |                  |
    						   |                  |                    |               <-----令牌有效-------
    						   |				  |                    |                |
    						   |                  |                    |                |-------------------
    						   |                  |                    |                |                  |
    						   |                  |                    |               <-----注册系统--------
    						   |                  |                    |                |
    						   |                  |                    |                |
    						   |				  <---------令牌有效----------------------
    						   |                  |                    |                |
    						   |                  |---------------------------          |
    						   |                  |                          |----令牌  |
    						   |                  |<---创建局部会话信息-------          |
    						   |                  |                    |                |  
    						   |<--受保护资源-----|                    |				|
    						   |
    						   |
    						   |
    						   |-----------------访问----------------->|                |
    						   |                                       |                |              
    						   |                                       | --验证未登陆   |   
    						   |                                       |            |   |
    						   |                                       |<------------   |
    						   |                                       |                |
    						   |                                       |-------调转----->
    						   |                                       |                |-----------------
    						   |                                       |                |                |
    						   |                                       |                |<---验证已登陆---				   
    						   |                                       |                |
    						   |                                       |                |
    						   |                                       |                |
    						   |                                       |--校验令牌------->
    						   |                                       |                |
    						   |                                       |                |------------------
    						   |                                       |                |				  |
    						   |                                       |                |<令牌有效---------
    						   |                                       |                |
    						   |                                       |                |------------------
    						   |                                       |<---------------|                 |
    						   |                                       |                |<--注册系统-------
    						   |                                       |                |
    						   |                                       |                |
    						   |                                       |                |
    						   |                                       |<-令牌有效------|
    						   |                                       |                |
    						   |                                       |                |
    						   |                                       |                |
    						   |                                       |------------
    						   |                                       |           |
    						   |                                       |<-----创建局部会话(令牌)
    						   |                                       |
    						   |                                       |
    						   |                                       |
    						   |<-----------受保护资源-----------------|				   
    				   
    			解释:
    				1:用户访问系统1的受保护资源,系统1发现用户未登录,跳转至sso认证中心,并将自己的地址作为参数
    				2:sso认证中心发现用户未登录,将用户引导至登录页面
    				3:用户输入用户名密码提交登录申请
    				4:sso认证中心校验用户信息,创建用户与sso认证中心之间的会话,称为全局会话,同时创建授权令牌
    				5:sso认证中心带着令牌跳转会最初的请求地址(系统1)
    				6:系统1拿到令牌,去sso认证中心校验令牌是否有效
    				7:sso认证中心校验令牌,返回有效,注册系统1
    				8:系统1使用该令牌创建与用户的会话,称为局部会话,返回受保护资源
    				9:用户访问系统2的受保护资源
    				10:系统2发现用户未登录,跳转至sso认证中心,并将自己的地址作为参数
    				12:sso认证中心发现用户已登录,跳转回系统2的地址,并附上令牌
    				13:系统2拿到令牌,去sso认证中心校验令牌是否有效
    				14:sso认证中心校验令牌,返回有效,注册系统2
    				15:系统2使用该令牌创建与用户的局部会话,返回受保护资源
    				16:用户登录成功之后,会与sso认证中心及各个子系统建立会话,用户与sso认证中心建立的会话称为全局会话,用户与各个子系统建立的会话称为局部会话,
    				   局部会话建立之后,用户访问子系统受保护资源将不再通过sso认证中心,全局会话与局部会话有如下约束关系
    				17:局部会话存在,全局会话一定存在
    				18:全局会话存在,局部会话不一定存在
    				19:全局会话销毁,局部会话必须销毁
    
    		注销:
    			单点登录自然也要单点注销,在一个子系统中注销,所有子系统的会话都将被销毁。
    			
    			图示:	
    					浏览器                  系统1               系统2                  sos认证中心
    					  |                       |                   |                         |
    					  |                       |                   |                         |
    					   ---------------------------------------------------------------------
    					  |                       |                   |                         |
    					  |						  | 				  |							|
    					  |                       |                   |                         |
    					  ---销毁请求(id)--------->
    					  |                       |                   |                         |
    					  |                       |-----------        |                         | 
    					  |                       |          |        |                         |
    					  |                       |<-取出令牌(会话id)
    					  |                       |                                             |
    					  |                       |                    |                        |
    											  ---------------------------------------------->
    					  |                       |                    |                        |
    					  |                       |                    |                        |----------------
    					  |                       |                    |                        |				|
    					  |                       |                    |                       |<--校验令牌有效(令牌)	
    					  |                       |                    |                        |                 
    					  |                       |                    |                        |
    					  |                       |                    |                        |-----------------																						
    					  |                       |                    |                        |                |
    					  |                       |                    |                        |<--销毁全局会话--(令牌)
    					  |                       |                    |                        |
    					  |                       |                    |                        |-----------------
    					  |                       |                    |                        |                |
    					  |                       |                    |                        |<-取出注册系统---(令牌)
    					  |                       |                    |                        |
    					  |                       |                    |                        |
    					  |                       |                    |<--销毁局部会话令牌-----|
    					  |                       |                    |                        |
    					  |                       |<---销毁全局会话令牌-------------------------|
    					  |                       |                    |                        |
    					  |<----------------------------登陆页面--------------------------------|
           				  
    			解释:
    				1:sso认证中心一直监听全局会话的状态,一旦全局会话销毁,监听器将通知所有注册系统执行注销操作
    				2:用户向系统1发起注销请求
    				3:系统1根据用户与系统1建立的会话id拿到令牌,向sso认证中心发起注销请求
    				4:sso认证中心校验令牌有效,销毁全局会话,同时取出所有用此令牌注册的系统地址
    				5:sso认证中心向所有注册系统发起注销请求
    				6:各注册系统接收sso认证中心的注销请求,销毁局部会话
    				7:sso认证中心引导用户至登录页面
    
    	4:部署图:
    		单点登录涉及sso认证中心与众子系统,子系统与sso认证中心需要通信以交换令牌、校验令牌及发起注销请求,
    		因而子系统必须集成sso的客户端,sso认证中心则是sso服务端,
    		整个单点登录过程实质是sso客户端与服务端通信的过程。
    		
    		 系统1-------httpClient---------------sso认证中心---------------httpClient---------系统2
    		   |                                       |                                         |
    		   |                                       |                                         |
    		   |                                       |                                         |
    		   |                                       |                                         |
    		   -------------------------------------------------------------------------------------
    		                                         防火墙
               -------------------------------------------------------------------------------------
    		        -                                    |
    				-                                    |
    				-                                    |
    				-                                    |
    			点击登陆应用,                           |
    			用户访问部署了单点登录的多系统应用群,   |
    			一次登录,到处使用                       |
    		                                             |
    													 |
    													 |
    												--------------
                                                      用户电脑												
    		 		
    	5:实现:
    		1:拦截子系统未登录用户请求,跳转至sso认证中心
    		2:接收并存储sso认证中心发送的令牌
    		3:与sso-server通信,校验令牌的有效性
    		4:建立局部会话
    		5:拦截用户注销请求,向sso认证中心发送注销请求
    		6:接收sso认证中心发出的注销请求,销毁局部会话sso-server
    		7:验证用户的登录信息
    		8:创建全局会话
    		9:创建授权令牌
    		10:与sso-client通信发送令牌
    		11:校验sso-client令牌有效性
    		12:系统注册
    		13:接收sso-client注销请求,注销所有会话
    		第一步:sos-client拦截未登录请求。
    		第二步:sos-aerver拦截未登录入请求。
    		第三步:sso-server验证用户登录信息。
    		第四步:sso-server创建授权令牌。
    		第五步:sso-client取的令牌并校验。
    		第六步:sso-server接收并处理校验令牌请求。
    		第七步:sso-client校验令牌成功创建局部会话。
    		第八步:注销过程。
    		
        6:代码:
    			/**
    			 * Created by Mloong on 2018/7/30
    			 * 实现单点登录
    			 */
    			var express = require('express');
    			var app = express();
    			var bodyparser = require('body-parser');
    			var crypto = require('crypto');
    			var session = require('express-session');
    			var cookie = require('cookie-parser');
    			var path = require('path');
    			var multipart = require('connect-multiparty');
    			var multipartMiddleware = multipart();
    			app.use(bodyparser.json());
    			var mdb;
    
    			/**
    			 * session,cookie中间件。
    			 */
    			app.use(cookie());
    			app.use(session({
    			    secret: 'secret', // 对session id 相关的cookie 进行签名
    			    resave: true,
    			    saveUninitialized: false, // 是否保存未初始化的会话
    			    cookie: {
    			        maxAge: 1000 * 60 * 3 // 设置 session 的有效时间,单位毫秒
    			    }
    			}));
    			//app.set('tem', __dirname); //设置模板的目录
    			//app.set('view engine', 'html'); // 设置解析模板文件类型:这里为html文件
    			//app.engine('html', require('ejs').__express); // 使用ejs引擎解析html文件中ejs语法
    			//app.use(bodyparser.json()); // 使用bodyparder中间件,
    			//app.use(bodyparser.urlencoded({ extended: true }));
    
    
    			/**
    			 * 连接mongodb
    			 */
    			var MongoClient = require('mongodb').MongoClient;
    			var url = "mongodb://localhost:27017/runoob";
    
    
    			/**
    			 * 生成令牌
    			 * 生成token
    			 * @return {string} return 返回值
    			 * */
    			function genToken()
    			{
    			    var buf = crypto.randomBytes(12);
    			    var token = buf.toString('hex');
    			    return token;
    			}
    
    
    			/**
    			 * 请求数据库
    			 */
    			MongoClient.connect(url, function (err, db)
    			{
    			    if (err) throw err;
    			    var dbo = db.db("runoob");
    			    mdb = dbo;
    			});
    
    			/**
    			 * 注册
    			 */
    			app.get('/register', function (req, res)
    			{
    			    res.sendFile(path.join(__dirname, './public/templates', 'register.html'));
    			});
    
    			app.post('/register', multipartMiddleware, function (req, res)
    			    {
    			        var username = req.body.user;
    			        var password = req.body.pwd;
    			        console.log(username);
    			        mdb.collection('user').findOne({username: username}, function (err, result)
    			        {
    			            if (err) throw err;
    			            if (result)
    			            {
    			                res.json({
    			                    ret_code: 1,
    			                    ret_msg: '用户名已存在请更换用户名!'
    			                });
    			            }
    			            else
    			            {
    			                mdb.collection('user').insertOne({usernaem: username, password: password}, function (err, result)
    			                {
    			                    if (err) throw err;
    			                    res.redirect('/login');
    			                });
    
    			            }
    			        });
    			    }
    			);
    
    			/**
    			 * 登录
    			 */
    			app.get('/login', function (req, res)
    			{
    			    res.sendFile(path.join(__dirname, './public/templates', 'login.html'));
    			});
    			app.post('/login', function (req, res)
    			{
    			    var username = req.body.user;
    			    var password = req.body.pwd;
    			    mdb.collection("user").findOne({username: username, password: password}, function (err, result)
    			    {
    			        if (err) throw err;
    			        if (result)
    			        {
    			            var ticket = genToken();
    			            mdb.collection('token').insertOne({ticket: ticket}, function (err, Lresult) {});
    			            req.session.ticket = ticket;
    			            res.cookie.ticket = ticket;
    			            res.redirect('/index');
    			        } else
    			        {
    			            res.json({
    			                ret_code: 1,
    			                ret_msg: '用户名或密码错误!'
    			            });
    			        }
    			    });
    			});
    
    			/**
    			 * 认证中心
    			 */
    			app.get('/authentication', function (req, res)
    			{
    			    if (req.session.ticket)
    			    {
    			        console.log("进入认证");
    			        var url = req.query.callback;
    			        var token = req.session.ticket;
    			        url = console.log(url + "?token=" + token);
    			        res.redirect(url);
    			    }
    			    else
    			    {
    			        res.redirect('/login');
    			    }
    			});
    
    			/**
    			 * 首页
    			 */
    			app.get('/index', function (req, res)
    			{
    			    if (req.session.ticket)
    			    {
    			        res.sendFile(path.join(__dirname, './public/templates', 'index.html'));
    			    }
    			    else
    			    {
    			        res.redirect('/login');
    			    }
    			});
    
    			/**
    			 * 注销
    			 */
    			app.post('/cancellation', function (req, res)
    			{
    			    var token = req.session.ticket;
    			    delete req.session.ticket;
    			    mdb.collection('user').removeOne({ticket: token}, function (ree, result)
    			    {
    			        if (err) throw err;
    			        res.redirect('/login');
    
    			    });
    
    			});
    			var server = app.listen(8881, function ()
    			{
    			    var host = server.address().address;
    			    var port = server.address().port;
    			    console.log("访问地址为 http://%s:%s", host, port);
    			});
    

      

  • 相关阅读:
    视频像素点级的标注
    unet
    Emmet缩写语法
    Nginx漏洞利用与安全加固
    算法时间复杂度
    动态规划dp
    数据结构Java实现04---树及其相关操作
    关于递归
    Java正则表达式
    Java String相关
  • 原文地址:https://www.cnblogs.com/w-s-l123/p/9458872.html
Copyright © 2011-2022 走看看