.NET - 在(Domino)服务器上使用基于表单的身份验证的 HTTP 服务

Posted

技术标签:

【中文标题】.NET - 在(Domino)服务器上使用基于表单的身份验证的 HTTP 服务【英文标题】:.NET - Consuming HTTP services on (Domino) server with form based authentication 【发布时间】:2012-01-04 18:18:27 【问题描述】:

我正在用 C# (.NET) 编写一个实用程序,它将使用 HTTP 从 Domino Web 服务器请求数据。

但是,此服务器使用基于表单的身份验证,而不是基本的 HTTP 身份验证。

我正在尝试了解如何编写代码以使用具有基于表单的身份验证的服务器执行 HTTP GETS/POSTS。

我已经尝试了所有我能想到的谷歌查询,但是一旦查询中出现“基于表单的身份验证”这个词,所有结果都只与实现服务服务器端有关,通常在 ASP.NET 或Sharepoint,没有关于从客户端使用此类服务​​的结果。

我从 Stack Overflow 中建议的相关问题中看到了 Java 代码,但是在其他语言的外国 API 中查找相关部分将是一次冒险。如果有可用的 .NET 示例代码或文档,我将不胜感激。

【问题讨论】:

【参考方案1】:

我相信有人可以提供更好的答案,但考虑到这一点,我会假设您托管 Web 服务的服务器具有某种登录机制来确定您已通过身份验证。所以我的方法是首先发布到登录页面,接受表单身份验证 cookie,然后继续执行您想要发出的任何后续请求。以下所有请求都已包含表单身份验证 cookie。

【讨论】:

谢谢...我只是想节省从头开始构建整个过程的时间。 我不确定你从头开始的意思,一个人如何在没有某种登录屏幕的情况下使用 Forms Authentication 进行身份验证? 我的意思是客户端代码从头开始。在搜索“cookie”一词时,我发现问题***.com/questions/2151576/… 似乎是一个几乎相同的用例,没有完整的周期——但它显示了 cookie 的关键处理。我可能正在路上。 酷,祝你好运。看到这是您在这个精彩网站上的第一篇文章,不要忘记投票和/或标记为回答所有有用的答案/建议。【参考方案2】:

感谢所有提供提示的人。

我想分享我开发的代码,以防它帮助其他人。虽然它是专门为 Domino 服务器编写的,但它应该很容易修改为任何基于 cookie 的身份验证服务器的帖子中的实际字段名称。

使用类:

    创建一个 DominoHttpSession,向其传递所有必要的属性,例如服务器名称、用户名和密码。 呼叫验证 尽可能多地调用 Get 或 GetXml 最终处置 DominoHttpSession,尽管它没有正式关闭,因为 HTTP 在技术上是无状态的。

限制:

这个简单的版本会因为 cookie 超时而失败。它不会尝试确定登录是否成功。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Xml.Linq;

namespace WebDomino


    /// <summary>
    /// A stateful (authenticated) session with a Domino server.  Current version only supports
    /// forms based authentication, and does not permit bypassing authentication.
    /// </summary>
    public class DominoHttpSession
    
        /// <summary>
        /// Username with which to authenticate to the Domino server, must be a legal web user name.
        /// </summary>
        public string UserName  set; get; 

        /// <summary>
        /// Web password of the authenticating account.
        /// </summary>
        public string Password  set; get; 

        /// <summary>
        /// The server on which the session will exist.  At this time, all connections must use
        /// the same server.  Untested but probably will work:  switching server name before establishing
        /// a connection, as long as the authentication cookies are shared.
        /// </summary>
        public string ServerHostName  set; get; 

        /// <summary>
        /// The session cookies.  Provided in case client code wants to analyze cookie content, but
        /// more likely only used internally to hold the authentication cookie from the server.
        /// </summary>
        public CookieContainer Cookies  get  return cookies;  

        private CookieContainer cookies = new CookieContainer();

        /// <summary>
        /// Sends an HTTP GET to the server, expecting an XML response.   
        /// </summary>
        /// <param name="url">The full url to GET; proper syntax is the responsibility of the caller.</param>
        /// <returns>The XElement representing the returned XML text</returns>
        public XElement GetXml(string url)
        
            return XElement.Parse(Get(url));
        

        public string Get(string url)
        
            var request = (HttpWebRequest)WebRequest.Create(url);

            request.CookieContainer = cookies;
            request.Method = "GET";

            using (var responseStream = request.GetResponse().GetResponseStream())
            using (var reader = new StreamReader(responseStream))
            
                var result = reader.ReadToEnd();
                return result;                
                                            
        

        /// <summary>
        /// Must be called to establish the session with the server.
        /// </summary>
        public void Authenticate()
                    
            ServicePointManager.Expect100Continue = false;

            var request = (HttpWebRequest)WebRequest.Create(String.Format("http://0//names.nsf?Login", ServerHostName));
            request.CookieContainer = cookies;
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            using (var requestStream = request.GetRequestStream())
            using (var writer = new StreamWriter(requestStream))
            
                writer.Write("Username=0&Password=1", UserName,Password);
            

            using (var responseStream = request.GetResponse().GetResponseStream())
            using (var reader = new StreamReader(responseStream))
            
                var result = reader.ReadToEnd();  

                // Success is assumed here--in production code it should not be
                                                       
        

        public ViewReader GetViewReader(string dbPath, string viewName)
        
            return new ViewReader(this)
                   
                       DbPath = dbPath,
                       View = viewName
                   ;
        

    



【讨论】:

【参考方案3】:

在基于会话的身份验证(您称之为“基于表单的身份验证”)期间,Domino 生成一个所谓的LTPA token (cookie) 以进一步对用户进行身份验证。

最简单的方法是模拟浏览器/用户,将带有必要表单数据的登录表单发送到服务器,从服务器响应中提取 LTPA cookie 并在进一步的请求中使用它。例如,您可以使用WatiN 来简化此操作。

或者您可以计算 cookie 的值,然后自己生成它。 LTPA cookie 的格式 ... 很容易通过 Google 找到,但这并不简单,您需要一些来自服务器的数据。

如果您要针对您认识的管理员执行此操作,您可以要求他通过add a Web Site rule which allows the use of basic authentication 获取请求的子集,而基于会话的身份验证用于网站的其余部分。

【讨论】:

谢谢,我想那些带有 LTPA 令牌的 Domino 特定方法可能会起作用......

以上是关于.NET - 在(Domino)服务器上使用基于表单的身份验证的 HTTP 服务的主要内容,如果未能解决你的问题,请参考以下文章

具有 Kerberos 身份验证和 XPages 的 Lotus Domino 服务器

Domino、CORS 和 OPTIONS 请求

UVA 211 The Domino Effect

Lotus Domino Designer中的源代码控制

JDBC无法与SQL Server建立SSL连接(Domino Java Agent FP 9)

Domino 10 有时不会在 Java 下解码 MIME 标头