nginx配置sso登录 您所在的位置:网站首页 sso单点登录配置 nginx配置sso登录

nginx配置sso登录

2023-04-04 09:24| 来源: 网络整理| 查看: 265

nginx配置sso登录

下面的例子是如何在nginx配置sso登录服务。

背景

用到几个主要元素:应用服务器(myweb),ngingx服务器,和认证服务器(mycas)。

为了验证的简化,所有的服务器都搭建在一台主机上(假设当前机器名为host.example.com),主机名即域名,三个服务通过三个不同的端口提供服务。

应用服务器,监听在主机端口4000。 CAS服务器,监听在主机端口3000。 nginx服务器,监听在主机端口80。

sso登录验证的基本流程

用户通过服务器端口80来请求访问资源。 端口80实际上是nginx的端口,真正的应用端口是4000;nginx会把请求最终路由到应用服务器端口4000上。 nginx通过配置文件的auth_request模块,把请求转向CAS服务器进行认证(假设http://host.example.com:3000/auth) 2.1. 如果用户没有在CAS服务器上经过登录认证,那么认证服务器返回401错误给nginx;nginx继续根据配置文件对401错误的处理方式,向用户浏览器返回302状态码,并附带一个认证服务器的跳转地址(http://host.example.com:3000/login),然后客户浏览器重新向认证服务器发起登录请求。用户在认证服务器上进行简单用户名密码验证: 2.1.1. 如果用户为合法用户:那么认证服务器将生成session,包含认证过的用户信息,以备将来的再次验证使用,并通过Set-cookie命令告知用户浏览器。用户通过此Cookie即可获得认证服务器的认可授权,此后用户带上此Cookie来访问认证服务器(http://host.example.com:3000/auth)时,认证服务器会返回200的状态码。 2.1.2. 如果用户为非法用户:那么认证服务器将不会session,这样用户无法获得认可的Cookie,那么当再次访问(http://host.example.com:3000/auth)时,会继续得到401错误的错误码,请求再次认证。 2.2. 假设用户已经授权成功,那么当用户访问服务器中的资源时,由于认证服务器(http://host.example.com:3000/auth)返回返回200状态码,服务器允许用户继续访问。

我们使用node/express来模拟应用服务器和CAS认证服务器。

步骤

安装nginx $ cat /etc/yum.repos.d/nginx.repo [nginx] name=nginx repo baseurl=http://nginx.org/packages/rhel/7/$basearch/ gpgcheck=0 enabled=1 $ sudo yum install nginx 安装node

参考官方文档,不细说。 https://nodejs.org/en/

安装express-generator

我们用它来生产node项目框架。

$ npm install express-generator -g

创建两个node项目

4.1. 创建应用服务器

$ express -e --git myweb $ cd myweb $ npm install

修改认证服务器端口为4000

$ cat bin/www var port = normalizePort(process.env.PORT || '4000');

4.2. 创建认证服务器

$ express -e --git mycase $ cd note $ npm install

保持认证服务器端口为3000

$ cat bin/www var port = normalizePort(process.env.PORT || '3000'); 修改nginx配置文件 $ cat /etc/nginx/nginx.conf user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; include /etc/nginx/conf.d/*.conf; server { listen 80 ; server_name host.example.com; location / { auth_request /auth; error_page 401 = @error401; auth_request_set $user $upstream_http_x_forwarded_user; proxy_set_header X-Forwarded-User $user; proxy_pass http://host.example.com:4000; } location /logout { proxy_pass http://host.example.com:4000/logout; } location /auth { internal; proxy_pass_request_body off; proxy_set_header Content-Length ""; proxy_set_header X-Original-URI $request_uri; proxy_pass http://host.example.com:3000; } location @error401 { add_header Set-Cookie "redirect=$scheme://$http_host$request_uri;Domain=.example.com;Path=/;Max-Age=3000"; return 302 http://host.example.com:3000/login; } } } 修改应用服务器app.js $ cat myweb/app.js var createError = require('http-errors'); var express = require('express'); var path = require('path'); var cookieParser = require('cookie-parser'); var logger = require('morgan'); var bodyparser = require('body-parser'); var expresssession = require('express-session'); var indexRouter = require('./routes/index'); var usersRouter = require('./routes/users'); var app = express(); // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'ejs'); app.use(logger('dev')); app.use(express.json()); app.use(express.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); app.use(bodyparser.json()); app.use(bodyparser.urlencoded({ extended: false })); app.use(expresssession({ secret: 'mysecret', resave: true, saveUninitialized: false, cookie: { maxAge: 1000 * 60 * 3 } })); app.get('/', function (req, res) { console.log("/ session.id =", req.session.id); console.log("/ session.user =", req.session.user); console.log("/ headers.user =", req.headers["user"]); console.log("/ cookies.user =", req.cookies["user"]); user = req.cookies["user"] if (user) { req.session.user= user; res.end('Welcome Page!'); } else { console.error("401 Unauthorized"); res.end('401 Unauthorized'); } }); app.get('/logout', function (req, res) { console.log("/ session.id =", req.session.id); console.log("/ session.user =", req.session.user); console.log("/ headers.user =", req.headers["user"]); req.session.destroy(); res.redirect('http://host.example.com:3000/logout'); }); app.use('/', indexRouter); app.use('/users', usersRouter); // catch 404 and forward to error handler app.use(function(req, res, next) { next(createError(404)); }); // error handler app.use(function(err, req, res, next) { // set locals, only providing error in development res.locals.message = err.message; res.locals.error = req.app.get('env') === 'development' ? err : {}; // render the error page res.status(err.status || 500); res.render('error'); }); module.exports = app; 修改认证服务器app.js $ cat mycas/app.js var createError = require('http-errors'); var express = require('express'); var path = require('path'); var cookieParser = require('cookie-parser'); var logger = require('morgan'); var bodyparser = require('body-parser'); var expresssession = require('express-session'); var cookie = require('cookie-parser'); var crypto = require('crypto'); var indexRouter = require('./routes/index'); var usersRouter = require('./routes/users'); var userTokens = {}; var userDatabase = { 'admin': 'admin' }; var app = express(); // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'ejs'); app.use(logger('dev')); app.use(express.json()); app.use(express.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); app.use(cookie()); app.use(bodyparser.json()); app.use(bodyparser.urlencoded({ extended: false })); app.use(expresssession({ secret: 'mysecret', resave: true, saveUninitialized: false, cookie: { maxAge: 1000 * 60 * 3 } })); app.get('/login', function (req, res) { console.log("/login req.session.id = ", req.session.id); console.log("/login req.headers = ", req.headers); res.sendFile(path.join(__dirname, './public/templates', 'login.html')); }); app.post('/login', function (req, res) { var user = req.body.username; var pass = req.body.password; console.log("/login POST req.session.id=", req.session.id); if (userDatabase.hasOwnProperty(user) && userDatabase[user] == pass) { // when username/password is valid var token = crypto.createHash('sha256').update(req.session.id).digest("hex") //req.session.user= user; //req.session.token= token; res.cookie('user', user); res.cookie('token', token); userTokens[token] = user; console.log("/login POST generate token[", token, "] for user [", user, "]"); res.redirect('http://host.example.com') } else { res.redirect('/login'); } }); app.get('/auth', function (req, res) { console.log("/auth session.id : " + req.session.id); console.log("/auth session.user : " + req.session.user); console.log("/auth session.token : " + req.session.token); console.log("/auth cookie.user : " + req.cookies.user); console.log("/auth cookie.token : " + req.cookies.token); token = req.cookies.token; user = req.cookies.user; if (userTokens[token] && userTokens[token] == user) { console.log("/auth return success"); res.setHeader("X-Forwarded-User", user); res.setHeader("user", user); res.end() } else { console.log("/auth return failure"); res.status(401); res.end() } }); app.get('/logout', function (req, res) { console.log("/logout req.session.id : " + req.session.id); req.session.destroy(); res.clearCookie("user"); res.clearCookie("token"); res.redirect('/login'); }); app.use('/', indexRouter); app.use('/users', usersRouter); // catch 404 and forward to error handler app.use(function(req, res, next) { next(createError(404)); }); // error handler app.use(function(err, req, res, next) { // set locals, only providing error in development res.locals.message = err.message; res.locals.error = req.app.get('env') === 'development' ? err : {}; // render the error page res.status(err.status || 500); res.render('error'); }); module.exports = app;

为认证服务器添加一个登录页面:

$ cat mycas/public/templates/login.html Insert title here body{ margin: 100px 0px; padding:0px; text-align:center; align:center; } input[type=text], input[type=password]{ width:20%; padding:7px 10px; margin: 8px 0; display:inline-block; border: 1px solid #ccc; box-sizing: border-box; } button{ background-color:#4CAF50; width: 10%; padding: 9px 5px; margin:5px 0; cursor:pointer; border:none; color:#ffffff; } button:hover{ opacity:0.8; } #un,#ps{ font-family:'Lato', sans-serif; color: gray; } Login Form Username: Password: Login 启动应用

启动认证服务器

$ DEBUG=myweb:* npm start

启动应用服务器

$ DEBUG=mycas:* npm start

启动nginx

$ sudo service nginx restart

nginx的错误日志在:/var/log/nginx/error.log

另外如果碰到如下错误: (13: Permission denied) while connecting to upstream:[nginx]

请参考下面链接: https://stackoverflow.com/questions/23948527/13-permission-denied-while-connecting-to-upstreamnginx

登录访问

登录 http://host.example.com 浏览器会跳转到登录页面,http://host.example.com:3000/login,输入用户名密码(admin/admin)后,跳转到应用服务器页面,显示"Welcome Page!"

退出 http://host.example.com/logout 退出后,页面重新跳转到登录页面。

关于应用服务器如何获取认证服务器的数据

11.1 设置request.Headers 在认证服务器,认证成功时:

app.get('/auth', function (req, res) { if (userTokens[token] && userTokens[token] == user) { res.setHeader("X-Forwarded-User", user); res.setHeader("X-Idcs-User", user); res.end() }

然后下nginx的配置文件里:

location / { auth_request_set $user $upstream_http_x_forwarded_user; proxy_set_header X-Forwarded-User $user; auth_request_set $idcsuser $upstream_http_x_idcs_user; proxy_set_header X-Idcs-User $idcsuser; }

从认证服务器的upstream获取x_forwarded_user和x_idcs_user,注意用小写,然后设置到应用服务器的request里面去。

11.2 设置浏览器cookie

在认证服务器的post/login成功时:

app.post('/login', function (req, res) { var user = req.body.username; var pass = req.body.password; console.log("/login POST req.session.id=", req.session.id); if (userDatabase.hasOwnProperty(user) && userDatabase[user] == pass) { res.cookie('user', user); res.cookie('token', token); } }

这样浏览器就能看到cookie的内容了。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有