dsapi开发domino登录认证的资料十分少,但是官方的资料讲解的很详细,要编写dsapi程序看官网的介绍十分必要,但是官网的资料仅仅提供了一个简单的登录demo的示例,复杂的功能还需要自己配合api去琢磨研究,现将自己研究的做一个记录。
1.domino环境配置介绍
A.软件下载地址
我们需要下载的lotus domino的软件包包括:
1)DOMI_SRV_9.01WIN_64_EN_FULL_-TRIAL(Lotus server9.0.1安装包)
这个是domino的核心组件,里面包括了domino server(用于首次配置服务参数、启动服务)和domino console(用于查看日志输入、命令行方式控制相关功能的开启,比如http服务的开停),如下图:
下载地址:http://www.ibm.com/developerworks/cn/downloads/ls/lsds/ (下面的地址链接为“下载试用版”的链接)
由于IBM网站下载软件,需要用已注册过的账号登录,故首次访问该地址会弹到登录页面,如下图:
登录后,会进入到下载页面,如下:
2)ND_Dgr_Admin_9.0.1_Wins_SC_DWks(domino admin工具包)这个工具主要用于用户方便配置domino服务
下载地址为:http://www.ibm.com/developerworks/downloads/ls/dominodesigner/
安装后图标为:
domino admin用于配置服务器,domino designer用于编写网页等
domino admin进入之后可以看到其可以配置
3)lotus notes
下载地址同1)一致,可以在页面靠后位置看到客户端工具包,如下图:
安装后图标为:
B.软件安装配置
1)domino server的安装配置
安装很简单,一直根据安装向导点击下一步即可,在此简单说一下配置
domino server的配置也基本是点击下一步即可,但是在如下的页面中需要用户输入密码、域名等,需要注意一下,配置如下图:
服务配置好后,可以通过domino console进行登录查看后台日志,如下图:
2)domino admin安装配置
2.dsapi开发资料
1)《利用 DSAPI 为 Domino Web 用户定制用户名和口令认证 》这篇是使用dsapi完成个性化认证的经典文章,是一篇入门级的文章,需要深读
2)要完成更深入的功能拓展,仅通过上面的文章里的内容是无法完成的,我们就需要下载dsapi的开发文档,借助api完成更深的内容,这个工具包可以在此下载:http://www.ibm.com/developerworks/develop/collaboration/index.html ,如下图,下载右边的IBM C and C++ API Toolkits for Notes and Domino 工具包:
3.dsapi研究内容
1)一个简单的dsapi dll的代码
dsapidemo.h
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <vector>
#include "dsapi/dsapi.h"
#ifdef SOLARIS
#include <shadow.h>
#endif
#ifdef AIX
#include <sys/types.h>
#include <pwd.h>
#endif
#ifdef HPUX
#include <pwd.h>
#include <crypt.h>
#include <unistd.h>
#endif
#include "dsapi/global.h"
#include "dsapi/osmem.h"
#include "dsapi/lookup.h"
STATUS FAR PASCAL MainEntryPoint (void);
unsigned int Authenticate(FilterContext* context, FilterAuthenticate* authData);
unsigned int FilterInit(FilterInitData* filterInitData);
unsigned int HttpFilterProc(FilterContext* context,unsigned int eventType, void* eventData);
dsapidemo.cpp
#include "stdafx.h"
#include "global.h"
#include "osmem.h"
#include "addin.h"
#include "dsapidemo.h"
STATUS FAR PASCAL MainEntryPoint(void)
{
return NOERROR;
}
unsigned int FilterInit(FilterInitData* filterInitData)
{
AddInLogMessageText("FilterInit start", NOERROR);
filterInitData->appFilterVersion = kInterfaceVersion;
filterInitData->eventFlags = kFilterAuthenticate;
strcpy(filterInitData->filterDesc,
"domino dsapi v1.0 Authentication Filter");
return kFilterHandledEvent;
}
unsigned int TerminateFilter(unsigned int reserved)
{
return kFilterHandledEvent;
}
unsigned int HttpFilterProc(FilterContext* context,
unsigned int eventType, void* eventData)
{
switch (eventType) {
case kFilterAuthenticate:
return Authenticate(context,
(FilterAuthenticate *)eventData);
break;
default:
break;
}
return kFilterNotHandled;
}
/*---
* 自定义用户登录处理函数
*/
unsigned int Authenticate(FilterContext* context,
FilterAuthenticate* authData)
{
if (authData->userName==NULL || authData->password==NULL){
AddInLogMessageText (string2, NOERROR);
return kFilterNotHandled;
}
else{
if (strcmp((const char*)authData->userName,"super")==0 && strcmp((const char*)authData->password,"password" )==0)
{
AddInLogMessageText ("super logged in successful", NOERROR);
authData->authType = kAuthenticBasic;
authData->foundInCache = TRUE;
return kFilterHandledEvent;
}
}
return kFilterNotHandled;
}
2) 使用dsapi实现页面地址跳转
跳转函数如下,采用的是修改header头文件的方式实现页面跳转
http协议中规定 :
301 redirect: 301 代表永久性转移(Permanently Moved)
302 redirect: 302 代表暂时性转移(Temporarily Moved )
本函数中使用302,是应为301跳转成功一次后,浏览器记住了跳转地址,以后再访问同一网址则不过服务器之间跳转到原先跳转过的地址,与根据业务同一网址跳转到不同的页面的思路相矛盾。
unsigned int rewritePageUrl(FilterContext* context, FilterAuthenticate* authData,std::string rewriteUrl) {
FilterResponseHeaders responseHeader;
responseHeader.responseCode = 302;
std::string logstr;
unsigned int iRetCodeWriteClient;
responseHeader.reasonText = "Moved temporary";
std::string responseHeaderText = "Location:" + rewriteUrl + "\r\n\r\n\r\n";
responseHeader.headerText = (char*)responseHeaderText.c_str();
context->ServerSupport(context, ServerSupportTypes::kWriteResponseHeaders, &responseHeader, NULL, 0, &iRetCodeWriteClient);
if (iRetCodeWriteClient == 0) {
authData->authType = kAuthenticBasic;
return kFilterHandledRequest;
}
else {
logstr = "rewrite client url error,errCode:" + iRetCodeWriteClient;
AddInLogMessageText((char*)logstr.c_str(), NOERROR);
return kFilterNotHandled;
}
}
3)通过网址跳转自动创建登录session
在HttpFilterProc中返回kFilterHandledEvent仅表示用户事件已处理,在登录中表示已认证成功,但是其并不代表建立的session。Domino Web建立session是在names.nsf默认的登录页面登录成功之后建立起来的,如果想通过地址跳转模拟names.nsf登录,可以将rewriteUrl地址写成如下形式:
redirectUrl = serverPath+"/names.nsf?login&username="+username+"&Password="+password+"&redirectto="+url;
4)验证用户已登录
通过函数ServerSupport获取到的用户信息中,当domino session建立了则authentricateUser.pWebUserName不为空,否则这个值为空
unsigned int iRetCodeAuthUser = 0;
FilterAuthenticatedUser authentricateUser;
authentricateUser.fieldFlags = FilterAuthenticatedUserFields::kWebUserName;
context->ServerSupport(context, ServerSupportTypes::kGetAuthenticatedUserInfo, &authentricateUser, NULL, 0, &iRetCodeAuthUser);
if (authentricateUser.pWebUserName != NULL && authentricateUser.pWebUserName!="") {
std::string cannonicalName(authentricateUser.pWebUserName);
logstr = "autherized the webUserName=" + cannonicalName;
AddInLogMessageText((char*)logstr.c_str(), NOERROR);
return kFilterNotHandled;
}
else {
logstr = "authentricateUser.pWebUserName = NULL";
AddInLogMessageText((char*)logstr.c_str(), NOERROR);
if ( casRemoteUserstr == "" && isOaResource==true) {
std::string customRewriteUrl = "http://"+customHostname + url;
return rewritePageUrl(context, authData, customRewriteUrl);
}
}
5)domino中使用dsapi
在domino admin中的配置-》服务器-》当前服务器文档-》Internet Protocol中修改选项DSAPI Filter file为自己编写的dll文件名称就行