统一身份认证(CAS)中文文档 请多指教
connect-cas2
一个完整的CAS Client NodeJS实现,支持CAS 2.0+ 协议。
CAS(Central Authentication Service) 是一个单点登录/登出的协议,下面的文档我们假设您已经对CAS比较熟悉,否则请先查看下CAS协议的介绍文档。
English version document
Install
npm install connect-cas2
特性
- 非代理模型下的CAS协议的登入、登出
- 代理模型下的CAS协议登入、登出、换取PT票据
- 单点登出
- Restlet integration
快速开始
注意:
- 务必在使用casClient.core()中间件之前初始化session
- 如果需要启用单点登出,并且您使用了bodyParser,那么必须在bodyParser之前使用casClient中间件。 因为CAS Client接收单点登出的请求需要拿到一个POST请求的RAW body,而在bodyParser之后并没有办法办到这个事情,因为bodyParser已经把请求拦截了。
var express = require('express');
var ConnectCas = require('connect-cas2');
var bodyParser = require('body-parser');
var session = require('express-session');
var cookieParser = require('cookie-parser');
var MemoryStore = require('session-memory-store')(session);var app = express();app.use(cookieParser());
app.use(session({name: 'NSESSIONID',secret: 'Hello I am a long long long secret',store: new MemoryStore() // or other session store
}));var casClient = new ConnectCas({debug: true,ignore: [/\/ignore/],match: [],servicePrefix: 'http://localhost:3000',serverPath: 'http://your-cas-server.com',paths: {validate: '/cas/validate',serviceValidate: '/buglycas/serviceValidate',proxy: '/buglycas/proxy',login: '/buglycas/login',logout: '/buglycas/logout',proxyCallback: '/buglycas/proxyCallback'},redirect: false,gateway: false,renew: false,slo: true,cache: {enable: false,ttl: 5 * 60 * 1000,filter: []},fromAjax: {header: 'x-client-ajax',status: 418}
});app.use(casClient.core());// NOTICE: If you want to enable single sign logout, you must use casClient middleware before bodyParser.
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));app.get('/logout', casClient.logout());// or do some logic yourself
app.get('/logout', function(req, res, next) {// Do whatever you like here, then call the logout middlewarecasClient.logout()(req, res, next);
});
Constructor
var casClient = new CasClient(options);
options
options.serverPath {String} (Required)
你的CAS Server的根路径。 如: https://www.your-cas-server-path.com
例: 如果你的options.paths.login='/cas/login'
, options.serverPath='https://www.your-cas-server-path.com'
, 那么将跳转到CAS的登陆页面的路径会被拼为:‘https://www.your-cas-server-path.com/cas/login’。
options.servicePrefix {String} (Required)
你网站的根路径。
例: 如果options.paths.validate='/cas/validate'
, options.servicePrefix='http://localhost:3000'
,那么你的client校验ticket的路径为: ‘http://localhost:3000/cas/validate’。
options.ignore {Array} (Optional, default: [])
有些情况下,你并不想所有请求都走CAS校验。设置ignore的规则,当规则命中时,CAS会直接跳过。
支持的规则有String/RegExp/Function类型。
我们将会这样校验各种类型的规则:
- String rules:
if (req.path.indexOf(stringRule) > -1) next();
- Reg rules:
if (regRule.test(req.path)) next();
- Function rules:
if (functionRule(req.path, req)) next();
options.match {Array} (Optional, default: []) (不推荐)
当设置这个选项时,仅有匹配规则的路由将会过CAS校验。不推荐使用。
规则设置同上。
options.paths {Object} (Optional)
CAS协议的各个路径配置, 包括CAS Client的和CAS Server的。
options.paths.validate (String) (Optional, default: ‘/cas/validate’)
(CAS Client)
用于Client侧校验ST的路径。
我们将会使用${options.servicePrefix}${options.paths.validate}
作为service
参数的取值,所有需要service参数的CAS Server的接口都会使用这个取值,比如: casServer/cas/login, casServer/cas/serviceValidate。
options.paths.proxyCallback (String) (Optional, default: ‘’)
(CAS Client)
在代理模型下,该路径用于CAS Client接受CAS Server的proxyCallback回调。该路径可以为相对路径或绝对路径(仅此配置支持绝对路径,因为某些场景下,可能CAS Server并不能直接通过域名访问CAS Client,此时可能需要配置为IP的绝对路径)
非代理模型下,请勿设置该选项。
如果你对代理模型与非代理模型有疑问,请阅读文档获取更多信息。
options.paths.serviceValidate (String) (Optional, default: ‘/cas/serviceValidate’)
(CAS Server)
CAS Server用于校验ticket的路径。
options.paths.proxy (String) (Optional, default: ‘/cas/proxy’)
(CAS Server)
换取proxy ticket用于与其他后台服务交互的路径。
options.paths.login (String) (Optional, default: ‘/cas/login’)
(CAS Server)
登陆的路径。
options.paths.logout (String) (Optional, default: ‘/cas/logout’)
(CAS Server)
注销的路径。
options.fromAjax {Object} (Optional, default: {})
默认情况下,当用户身份过期时,CAS client会让用户302到登陆页面。但是当这个请求是一个AJAX请求时,AJAX并不能感知这个302,而是会直接访问302之后的路径,那么此时会有两种情况:
- client与server同域,那么AJAX返回的将会是一个HTMl字符串(登录页面),然后直接JS解析报错。
- client与server跨域,那么AJAX会直接报CROS的错
所以为了避免这种情况发生,增加了这个配置。
options.fromAjax.header {String} (Optional, default: ‘x-client-ajax’)
设置了这个配置后,CAS client会认为所有带有以这个字段为key的请求头的请求都是一个AJAX请求,此时如果用户身份过期,那么将不会返回302响应码,而是返回options.fromAjax.status
的状态码。
options.fromAjax.status {Number} (Optional, default: 418)
如上所述,当判断是AJAX请求,且身份过期,返回这个状态码
这样设置后,您还需要在前端代码中做这些事情:
- 给你的所有AJAX请求带上以
'x-client-ajax'
为key,value不为空的请求头,如:'x-client-ajax': 1
。 - 当AJAX响应收到约定的状态码,表示用户身份已过期,此时调用
window.location.reload()
或是别的事情来让你的用户重新获取身份。
options.debug {Boolean} (Deprecated)
原本这个选项是用于控制是否输出所有log,但是因为CAS协议的复杂性,我们建议哪怕是生产环境也要输出所有日志,故废弃了该字段。
另外,生产环境下,我们建议使用自定义的logger,对于输入日志的级别您可以自行在logger中控制。
options.redirect(req, res) {Function} (Optional, default: null)
默认情况下,用户登录后,或是登录失败后,都会重定向到最后一次访问的路径,设置这个选项可以改变这个行为。
当您需要自行处理重定向逻辑时,配置redirect函数, 并且返回您想要重定向的路径字符串, 如: ‘/somewhere’.
大部分场景您都不需要配置该项,除了一些比较特殊的场景,比如说某些页面当用户注销后您不希望用户直接跳到登陆页,而是可以继续浏览,具体的操作请看下面的例子:
var options = {redirect: function(req, res) {// 在redirect中, 根据是否有特殊cookie来决定是否跳走if (req.cookies.logoutFrom) {// 返回您想要重定向的路径return url.parse(req.cookies.logoutFrom).pathname;}}
};var casClient = new CasClient(options)app.get('/logout', function(req, res) {var fromWhere = req.get('Referer');var fromWhereUri = url.parse(fromWhere);// 根据来源判断是否是你不希望用户注销后登陆的页面,如果是的话,设置设置cookieif (fromWhereUri.pathname.match(/the page you dont want user to login after logout/)) {res.cookie('logoutFrom', fromWhereUri.pathname);}casClient.logout()(req, res);
});
options.cache {Object} (Optional) Since v1.1.0-beta
(仅在代理模型下有用)
当你的后端支持PT缓存并且开始缓存后,您可以设置options.cache.enable
为true来启用PT缓存,在有效期内,对于一个targetService都会使用缓存的PT。
注意过期时间的设置,推荐client侧的过期时间略短于后端,万一client侧的PT未过期,后端server的PT已过期,那么使用该pt请求将会收到响应码401,此时您需要手动调用req.getProxyTicket(targetService, {renew: true}, callback)
来重新获取一个新的PT。
更多信息请查看req.getProxyTicket
的介绍。
(注意:启用此选项前您必须确认您的后代服务是否已启动缓存,否则单在client侧缓存不会起任何作用,因为默认PT是用一次就过期的。)
options.cache.enable {Boolean} (Optional, 默认为false)
设置为true来开始Client侧的PT缓存
options.cache.ttl {Number} (Optional, 默认为 300000, 单位毫秒)
过期时间,单位毫秒
options.cache.filter {Array} (Optinal, default: [])
某些场景下,特别是当您需要与多个后端服务交互数据时,可能并不是每个服务都开启了缓存,此时可以通过此配置设置规律规则。
任何一条规则匹配都将直接不使用缓存。规则匹配规则同options.ignore
。
options.restletIntegration {Object} (Optional, defualt: {})
配置你的restlet integration。
当使用restlet integraion时, 用户不需要登录, 并且能够通过访问一个CAS Server的特殊接口获取一个特殊的PGT, 用这个PGT可以向CAS Server换取PT, 并与特殊的一个后端服务交互数据.
options.restletIntegration是一个对象, 其中key代表的特定的restlet integration的规则名, value是一个对象, 需要包含两个属性: trigger {Function}, params {Object},
其中trigger决定了是否使用该条规则的参数来获取PGT, params决定了要向接口传递什么参数.
对于使用restlet integration的PGT获取PT的过程用户不需要关注, 仍与调普通后端接口一样先用req.getProxyTicket获取pt, 再发送请求即可.
对于我们自己的使用场景, 是用于设置DEMO产品. 当用户访问特定DEMO产品时, trigger中判断访问的路径与产品Id, 匹配时trigger返回true, 然后在调用req.getProxyTicket时会自动去获取PGT, 然后自动换PT, 与普通接口一样使用.
Example:
options.restletIntegration: {demo1: {trigger: function(req) {// Decision whether to use restlet integration, when matched, return true.// Then CAS will not force the user to login, but can get a PT and interacted with the specific back-end service that support restlet integration by a special PGT. // return false},// Parameters that will send to CAS server to get a special PGTparams: {username: 'restlet username',from: 'http://localhost:3000/cas/validate',password: 'restlet password'}}
}
options.hooks {Object} (Optional, since v1.1.24)
casClient.core()中间件的钩子函数, 目前支持两个钩子函数, 触发时机分别是请求流进入cas中间件与结束中间件, 您可以在这其中添加监控、耗时等业务逻辑. 钩子函数将会被如同中间件一样调用.
options.hooks.before {Function}
当请求流进入casClient.core()中间件时被调用, 他将会被如同中间件一样被调用: options.hooks.before(req, res, next)
.(不要忘记最后调用next()
)
options.hooks.after {Function}
当casClient.core()中间件的所有业务逻辑执行结束后被调用, 它的调用方法同上, 再次提醒, 不要忘记最后调用next()
.
options.logger {Function} (Optional)
一个自定义logger的工厂函数。接受两个参数 req
与type
,req
是Express的Response对象,type
是一个字符串,为这三个之一: ‘log’, ‘error’, ‘warn’。
该函数根据type的不同返回对应的用于打印日志的函数。 比如默认情况下,使用的系统的console对象下的函数:options.logger = (req, type) => return console[type].bind(console[type])
。
在生产环境下,您可能需要自定义输出日志的格式、内容、输出方式,可能会用到log4js、winston等组件, 这些场景下, 您可能需要设置options.logger
配置。
在我们自己项目的使用场景下,我们甚至需要给每一条日志打上用户与ip的信息,这也是为什么会将Request对象传给工厂函数。
下面是一个我们实际使用时的例子:
app.use((req, res, next) => {req.sn = uuid.v4();function getLogger(type = 'log', ...args) {let user = 'unknown';try {user = req.session.cas.user;} catch(e) {}return console[type].bind(console[type], `${req.sn}|${user}|${req.ip}|`, ...args);}req.getLogger = getLogger;
});var casClient = new CasClient({logger: (req, type) => {return req.getLogger(type, '[CONNECT_CAS]: ');}
});app.use(casClient.core());
方法
casClient.core()
返回casClient的核心中间件,处理了几乎所有CAS协议相关的业务逻辑。
使用: app.use(casClient.core())
。
casClient.logout()
返回处理注销逻辑的中间件,注销session、然后重定向到CAS Server的注销页面。
您可以直接使用该中间件:app.get('/logout', casClient.logout())
,
也可以在处理您自己的业务逻辑后手动调用该中间件:
app.get('/logout', function(req, res) {// Do your logic here, then call the logout middlecasClient.logout()(req, res)});
req.getProxyTicket(targetService, [proxyOptions], callback)
在使用casClient.core()
中间件后,您可以在req对象上获取一个getProxyTicket
函数。
当您使用代理模型时,您可以通过该方法来获取一个用于与后端服务交互数据的PT,当非代理模型下,调用该函数会直接执行回调,参数为空。
targetService
{String} 是您需要访问的后端服务的认证ticket的完整路径。您需要确认您的后端服务使用的是什么cas client,配置如何,如使用Java的shiro-cas库,那么默认路径为: http://server.com/shiro-cas,如果也是使用NodeJS的connect-cas2,那么路径将为: http://nodeserver.com/cas/validate
proxyOptions
{Object} (Optional) 获取PT的选项
proxyOptions.disableCache
{Boolean} 如果设置为true,将会跳过缓存直接获取一个新的PT
proxyOptions.renew
{Boolean} 如果设置为true,将会跳过缓存直接获取一个新的PT,随后将新的PT设置进缓存,覆盖旧的缓存PT
Example:
app.get('/api', function(req, res) {var service = 'http://your-service.com';req.getProxyTicket(service + '/cas', function ptCallback(err, pt) {if (err) return res.status(401).send('Error when requesting PT, Authentication failed!');request.get(service + '/api/someapi?ticket=' + 'pt', function (err, response) {if (err) return res.sendStatus(500);// 如果在client pt未过期,而server上pt已过期,此时会返回401,手段设置renew重新获取if (response.status == 401) {// 注意跳出逻辑,避免由于身份问题的401导致死循环return req.getProxyTicket(service + '/cas', {renew: true}, ptCallback);}res.send(response);});});});
请多多指教
统一身份认证(CAS)中文文档 请多指教相关推荐
- php邮箱验证laravel接口,Email认证 | Laravel 中文文档 - 码农教程
简介 许多 web 应用要求用户在使用之前进行 Email 地址验证.Laravel 不强迫你在每个应用中重新实现它,Laravel提供了方便的方法来发送和验证电子邮件验证请求. Model 预备 开 ...
- 【集合】统一身份认证(CAS)和OAuth2的工作流程
一.CAS协议 单点登录SSO(Single Sign ON),指在多个应用系统中,只需登录一次,即可在多个应用系统之间共享登录.如:在学校登录了OA系统,再打开科研.教务系统,都会实现自动登录. 统 ...
- Greenplum 6.9 资源组中文文档
本文更新版本:http://www.200yi.com/ff_internal/wiki.php?id=wiki:Database:Greenplum:资源管理:Greenplum%206.9%20资 ...
- 统一身份认证系统的简单看法
[事件背景]洋葱服务为什么没被成功接盘?_搜狐科技_搜狐网 https://www.sohu.com/a/124452755_354899 今天无意中看到这则新闻,发现人家洋葱认证服务已经停运1年多啦 ...
- App.js实现使用js开发app的应用,此文是中文文档
在阅读前,在此说明下,本人英文一直不好,所以该文档是借助翻译工具翻译的,阅读起来可能有点不好,请各位谅解,哪位大神有标准的中文文档请分享下 Github下载地址:https://github.com/ ...
- 统一身份认证子系统界面设计与实现
目 录 一 引言 -------------------------1 二 需求分析-----------------------..2 三 总体设计-----------------------. ...
- LDAP服务器ca系统,基于LDAP的统一身份认证系统与CA认证的集成.pdf
基于LDAP的统一身份认证系统与CA认证的集成 , 第 33 卷 第 8 期 宜春学院学报 Vol. 33 No. 8 2011 年 8 月 Journal of Yichun College Aug ...
- springmvc--sso单点登录cas统一身份认证器
开发环境 maven idea Windows 10 JDK 1.8+ 域名解析的配置 这里通过SwitchHosts来实现:以管理员身份打开 前两个:两个客户端应用的域名 后一个:是服务端的域名. ...
- cas如何实现多系统间的相互认证_统一身份认证和单点登录的区别
首先大家会遇到这样一个问题,统一身份认证和单点登录的概念是什么? 百度百科对统一身份认证的定义 所谓身份认证,就是判断一个用户是否为合法用户的处理过程.最常用的简单身份认证方式是系统通过核对用户输入的 ...
- CAS统一身份认证(四):集成MySQL用户验证
本文主要介绍CAS统一身份认证服务器JDBC密码管理,并以FreeBSD环境下的MySQL数据库为例实现CAS 6.6版的数据库用户验证.主要包括以下几个方面: JDBC密码管理 MySQL数据库准备 ...
最新文章
- Linux存储的基本管理
- 字符串的第n个排列的算法
- 最短路 poj1125
- 编程语言:C语言与Java的细致对比,你知道选谁了吗?
- am5728 是否支持aarch64_AM5728高性能音视频处理开发板介绍
- 基于JAVA+SpringBoot+Mybatis+MYSQL的美食分享网站
- opencv python3 找图片不同_基于OpenCV-python3实现抠图
- SQL server 数据库调用远程数据库存储过程的实现方法
- 精读《手写 SQL 编译器 - 回溯》 1
- LINUX下载编译x265
- C++定义一个对象和new一个对象的区别与联系
- windows7 x64x86专业纯净版(usb3.0_nvme)2019.12.17
- Windows进程小结
- 脱胎于沃尔沃的Polestar 2浮出水面,它真能挑战Model 3吗?
- 故障智能诊断读书笔记(一)
- 管理学总论之管理活动、管理思想和古典管理理论
- 盘点最受欢迎的十大技术文章
- 有哪些epub转txt方法?快把这些转换方法收藏起来吧
- java 复合方法_《Java 8 实战》Ch3: Lambda表达式(下):类型与限制、方法引用、复合...
- ubuntu创建虚拟硬盘
热门文章
- java中的private访问控制
- 学海无涯!最全Android面试知识点梳理,系列篇
- python绘制国际象棋规则口诀_国际象棋摆棋口诀
- 手机水星路由器服务器无响应,水星路由器无线wifi连接成功但上不了网的解决方法...
- 禁用搜狗输入法Linux版的Ctrl+Shift+F的简繁切换快捷键
- 四川全国计算机一级考试查询系统,2013四川计算机一级成绩查询入口
- 科学计算机怎么算四分位数,科学网—四分位数间距 - 贺小星的博文
- DellR720安装系统不能正常进入系统
- Ubuntu设置开机启动项目
- Qt开发笔记之编码h264码流并封装mp4(六):ubuntu平台编译mp4v2并封装mp4