单点登录

转载单点登录

oken;
24   //如果url带有token,则表明已经在passport鉴权过
25   if (token) {
26     //存在token,则在内存中寻找之前与用户的映射关系
27     //异步的
28     fs.readFile(token_path, 'utf8', function (err, data) {
29       if (err) throw err;
30       if (!data) data = '{}';
31       data = JSON.parse(data);
32       //如果存在标志,则验证通过
33       if (data[token]) {
34         res.redirect('http://' + from + '?token=' + token);
35         return;
36       }
37       //如果不存在便引导至登录页重新登录
38       res.redirect('/');
39     });
40   } else {
41     res.render('index', {
42       title: '统一登录passport'
43     });
44   }
45 });
46 
47 router.post('/', function (req, res, next) {
48   if (!req.query.from) return;
49   var name = req.body.name;
50   var pwd = req.body.password;
51   var from = req.query.from;
52   var token = new Date().getTime() + '_';
53   var cookieObj = {};
54   var token_path = path.resolve() + '/token_user.json';
55   //简单验证
56   if (name === pwd) {
57     req.flash('success', '登录成功');
58     //passport生成用户凭证,并且生成令牌入cookie返回给子系统
59     token = token + name;
60     res.setHeader("Set-Cookie", ['token=' + token]);
61     //持久化,将token与用户的映射写入文件
62     fs.readFile(token_path, 'utf8', function (err, data) {
63       if (err) throw err;
64       if (!data) data = '{}';
65       data = JSON.parse(data);
66       //以token为key
67       data[token] = name;
68       //存回去
69       fs.writeFile(token_path, JSON.stringify(data), function (err) {
70         if (err) throw err;
71       });
72     });
73     res.redirect('http://' + from + '?token=' + token);
74   } else {
75     console.log('登录失败');
76   }
77 });
78 module.exports = router;
复制代码

子系统A的实现

复制代码
 1 var express = require('express');
 2 var router = express.Router();
 3 var request = require('request');
 4 
 5 /* GET home page. */
 6 router.get('/', function (req, res, next) {
 7   var token = req.query.token;
 8   var userid = null;
 9   //如果本站已经存在凭证,便不需要去passport鉴权
10   if (req.session.user) {
11     res.render('index', {
12       title: '子产品-A-' + req.session.user,
13       user: req.session.user
14     });
15     return;
16   }
17   //如果没有本站信息,又没有token,便去passport登录鉴权
18   if (!token) {
19     res.redirect('http://passport.com?from=a.com');
20     return;
21   }
22   //存在token的情况下,去passport主站检查该token对应用户是否存在,
23   //存在并返回对应userid
24   //这段代码是大坑!!!设置的代理request不起效,调了3小时
25   request(
26     'http://127.0.0.1:3000/check_token?token=' + token + '&t=' + new Date().getTime(),
27     function (error, response, data) {
28       if (!error && response.statusCode == 200) {
29         data = JSON.parse(data);
30         if (data.code == 0) {
31           //这里userid需要通过一种算法由passport获取,
32           //这里图方便直接操作token
33           //因为token很容易伪造,所以需要去主战验证token的有效性,
34           //一般通过webservers 这里验证就简单验证即可......
35           userid = data.userid;
36           //有问题就继续登录
37           if (!userid) {
38             res.redirect('http://passport.com?from=a.com');
39             return;
40           }
41           //取得userid后,系统便认为有权限去数据库根据用户id获取用户信息
42           //根据userid操作数据库流程省略......
43           // req.session.user = userid;
44           res.render('index', {
45             title: '子产品-A-' + userid,
46             user: userid
47           });
48           return;
49         } else {
50           //验证失败,跳转
51           res.redirect('http://passport.com?from=a.com');
52         }
53       } else {
54         res.redirect('http://passport.com?from=a.com');
55         return;
56       }
57     });
58 });
59 module.exports = router;
复制代码

passport鉴权程序模拟

复制代码
 1 var express = require('express');
 2 var router = express.Router();
 3 var path = require('path');
 4 var fs = require('fs'); 
 5 
 6 /* GET users listing. */
 7 router.get('/', function(req, res, next) {
 8   var token = req.query.token;
 9   var ret = {};
10   var token_path = path.resolve() + '/token_user.json';
11   ret.code = 1;//登录失败
12   if(!token) {
13     res.json(ret);
14     return;
15   }
16   //如果传递的token与cookie不等也认为是鉴权失败
17   // if(token != cookieObj['token']){
18   //     res.json(ret);
19   //   return;
20   // }
21   fs.readFile(token_path, 'utf8', function (err, data) {
22         if (err) throw err;
23         if(!data) data = '{}';
24         data = JSON.parse(data);
25         //如果存在标志,则验证通过,未考虑账号为0的情况
26         if(data[token]) {
27             ret.code = 0;//登录成功
28             ret.userid = data[token];
29         }
30         res.json(ret);
31     });
32 });
33 module.exports = router;
复制代码

简单测试

测试之前需要设置host,这里继续采用fiddler神器帮助:

这边直接用node跑了3个服务器:

然后打开浏览器输入a.com,直接跳到了,登录页:

简单登录后(账号密码输入一致即可):

这个时候直接进入子系统B:

直接便登录了,说明方案大体上是可行的

结语

首先,这里的程序很简陋,很多问题,也没有做统一退出的处理,今天主要目的是了解单点登录,后面有实际工作再求深入。

这里附上源码,感兴趣的朋友看看吧:http://files.cnblogs.com/files/yexiaochai/web.rar,注意依赖包

原文地址:https://www.cnblogs.com/Leo_wl/p/4449293.html