connect-cas2

一个完整的CAS Client NodeJS实现,支持CAS 2.0+ 协议。

CAS(Central Authentication Service) 是一个单点登录/登出的协议,下面的文档我们假设您已经对CAS比较熟悉,否则请先查看下CAS协议的介绍文档。

English version document

Install

npm install connect-cas2

特性

  1. 非代理模型下的CAS协议的登入、登出
  2. 代理模型下的CAS协议登入、登出、换取PT票据
  3. 单点登出
  4. Restlet integration

快速开始

注意:

  1. 务必在使用casClient.core()中间件之前初始化session
  2. 如果需要启用单点登出,并且您使用了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类型。

我们将会这样校验各种类型的规则:

  1. String rules:
if (req.path.indexOf(stringRule) > -1) next();
  1. Reg rules:
if (regRule.test(req.path)) next();
  1. 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之后的路径,那么此时会有两种情况:

  1. client与server同域,那么AJAX返回的将会是一个HTMl字符串(登录页面),然后直接JS解析报错。
  2. 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请求,且身份过期,返回这个状态码

这样设置后,您还需要在前端代码中做这些事情:

  1. 给你的所有AJAX请求带上以'x-client-ajax'为key,value不为空的请求头,如: 'x-client-ajax': 1
  2. 当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的工厂函数。接受两个参数 reqtypereq是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)中文文档 请多指教相关推荐

  1. php邮箱验证laravel接口,Email认证 | Laravel 中文文档 - 码农教程

    简介 许多 web 应用要求用户在使用之前进行 Email 地址验证.Laravel 不强迫你在每个应用中重新实现它,Laravel提供了方便的方法来发送和验证电子邮件验证请求. Model 预备 开 ...

  2. 【集合】统一身份认证(CAS)和OAuth2的工作流程

    一.CAS协议 单点登录SSO(Single Sign ON),指在多个应用系统中,只需登录一次,即可在多个应用系统之间共享登录.如:在学校登录了OA系统,再打开科研.教务系统,都会实现自动登录. 统 ...

  3. Greenplum 6.9 资源组中文文档

    本文更新版本:http://www.200yi.com/ff_internal/wiki.php?id=wiki:Database:Greenplum:资源管理:Greenplum%206.9%20资 ...

  4. 统一身份认证系统的简单看法

    [事件背景]洋葱服务为什么没被成功接盘?_搜狐科技_搜狐网 https://www.sohu.com/a/124452755_354899 今天无意中看到这则新闻,发现人家洋葱认证服务已经停运1年多啦 ...

  5. App.js实现使用js开发app的应用,此文是中文文档

    在阅读前,在此说明下,本人英文一直不好,所以该文档是借助翻译工具翻译的,阅读起来可能有点不好,请各位谅解,哪位大神有标准的中文文档请分享下 Github下载地址:https://github.com/ ...

  6. 统一身份认证子系统界面设计与实现

    目  录 一 引言 -------------------------1 二 需求分析-----------------------..2 三 总体设计-----------------------. ...

  7. LDAP服务器ca系统,基于LDAP的统一身份认证系统与CA认证的集成.pdf

    基于LDAP的统一身份认证系统与CA认证的集成 , 第 33 卷 第 8 期 宜春学院学报 Vol. 33 No. 8 2011 年 8 月 Journal of Yichun College Aug ...

  8. springmvc--sso单点登录cas统一身份认证器

    开发环境 maven idea Windows 10 JDK 1.8+ 域名解析的配置 这里通过SwitchHosts来实现:以管理员身份打开 前两个:两个客户端应用的域名 后一个:是服务端的域名. ...

  9. cas如何实现多系统间的相互认证_统一身份认证和单点登录的区别

    首先大家会遇到这样一个问题,统一身份认证和单点登录的概念是什么? 百度百科对统一身份认证的定义 所谓身份认证,就是判断一个用户是否为合法用户的处理过程.最常用的简单身份认证方式是系统通过核对用户输入的 ...

  10. CAS统一身份认证(四):集成MySQL用户验证

    本文主要介绍CAS统一身份认证服务器JDBC密码管理,并以FreeBSD环境下的MySQL数据库为例实现CAS 6.6版的数据库用户验证.主要包括以下几个方面: JDBC密码管理 MySQL数据库准备 ...

最新文章

  1. Linux存储的基本管理
  2. 字符串的第n个排列的算法
  3. 最短路 poj1125
  4. 编程语言:C语言与Java的细致对比,你知道选谁了吗?
  5. am5728 是否支持aarch64_AM5728高性能音视频处理开发板介绍
  6. 基于JAVA+SpringBoot+Mybatis+MYSQL的美食分享网站
  7. opencv python3 找图片不同_基于OpenCV-python3实现抠图
  8. SQL server 数据库调用远程数据库存储过程的实现方法
  9. 精读《手写 SQL 编译器 - 回溯》 1
  10. LINUX下载编译x265
  11. C++定义一个对象和new一个对象的区别与联系
  12. windows7 x64x86专业纯净版(usb3.0_nvme)2019.12.17
  13. Windows进程小结
  14. 脱胎于沃尔沃的Polestar 2浮出水面,它真能挑战Model 3吗?
  15. 故障智能诊断读书笔记(一)
  16. 管理学总论之管理活动、管理思想和古典管理理论
  17. 盘点最受欢迎的十大技术文章
  18. 有哪些epub转txt方法?快把这些转换方法收藏起来吧
  19. java 复合方法_《Java 8 实战》Ch3: Lambda表达式(下):类型与限制、方法引用、复合...
  20. ubuntu创建虚拟硬盘

热门文章

  1. java中的private访问控制
  2. 学海无涯!最全Android面试知识点梳理,系列篇
  3. python绘制国际象棋规则口诀_国际象棋摆棋口诀
  4. 手机水星路由器服务器无响应,水星路由器无线wifi连接成功但上不了网的解决方法...
  5. 禁用搜狗输入法Linux版的Ctrl+Shift+F的简繁切换快捷键
  6. 四川全国计算机一级考试查询系统,2013四川计算机一级成绩查询入口
  7. 科学计算机怎么算四分位数,科学网—四分位数间距 - 贺小星的博文
  8. DellR720安装系统不能正常进入系统
  9. Ubuntu设置开机启动项目
  10. Qt开发笔记之编码h264码流并封装mp4(六):ubuntu平台编译mp4v2并封装mp4