【问题标题】:Authentication to ASP.NET Web Api using ADFS使用 ADFS 对 ASP.NET Web Api 进行身份验证
【发布时间】:2017-07-04 05:45:34
【问题描述】:

我需要访问使用 ADFS 进行身份验证的 ASP.NET Web Api。通过 ADFS 登录门户并获取相关的 FedAuth cookie,我可以通过浏览器可靠地访问它。不幸的是,我需要从专用浏览器外部访问它才能在移动应用程序中使用。该项目几乎是为工作和学校身份验证(本地)设置并设置为 cookie 身份验证的标准 Visual Studio Web API 模板的略微修改版本。

来自 Startup.Auth.cs 的一些代码:

public void Configuration(IAppBuilder app)
{
    app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
    app.UseWsFederationAuthentication(
        new WsFederationAuthenticationOptions
        {
            Wtrealm = realm,
            MetadataAddress = adfsMetadata
        });
    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationType = WsFederationAuthenticationDefaults.AuthenticationType
    });
}

我似乎不知道从哪里开始。我尝试从 ADFS 请求访问令牌,并且可以使用相关登录信息获取不同版本的 SAML 断言,但它被 Web API 拒绝。我是否误解了它应该如何工作?

据我了解,它应该是这样的: How I think it's supposed to work

  1. 应用从 ADFS 请求身份验证令牌
  2. 如果提供的信息正确,ADFS 会给请求者一个身份验证令牌
  3. 应用程序向 Web API 发出请求,并将令牌作为 base64 编码字符串发送到名为 FedAuth(默认情况下)的 cookie 中
  4. Web Api 将令牌发送到 ADFS 以查明令牌是否正确。
  5. ADFS 响应某种成功消息
  6. Web Api 以拒绝或数据片段响应应用程序,具体取决于身份验证的方式。

这就是我现在试图弄清楚如何获得正确令牌时所拥有的。

using System;
using System.IdentityModel.Protocols.WSTrust;
using System.IdentityModel.Tokens;
using System.Net;
using System.Net.Http;
using System.ServiceModel;
using System.ServiceModel.Security;
using Thinktecture.IdentityModel.Extensions;
using Thinktecture.IdentityModel.WSTrust;

namespace ConsoleApplication1
{    
    class Program
    {
        private const string UserName     = "USERNAME";
        private const string Password     = "PASSWORD";
        private const string Domain       = "DOMAIN";
        private const string ADFSEndpoint = "ADFS ENDPOINT";
        private const string ApiBaseUri   = "THE API";
        private const string ApiEndPoint  = "AN ENDPOINT";

        static void Main(string[] args)
        {
            SecurityToken token = RequestSecurityToken(); // Obtain security token from ADFS.
            CallApi(token);                               // Call api. 
            Console.ReadKey();                            // Stop console from closing
        }

        private static SecurityToken RequestSecurityToken()
        {
            var trustChannelFactory =
                new WSTrustChannelFactory(new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
                    new EndpointAddress(new Uri(ADFSEndpoint)))
                {
                    TrustVersion = TrustVersion.WSTrust13,
                    Credentials = { UserName = { UserName = UserName + "@" + Domain, Password = Password } },
                };

            var requestSecurityToken = new RequestSecurityToken
            {
                RequestType = RequestTypes.Issue,
                KeyType = KeyTypes.Bearer,
                AppliesTo = new EndpointReference(ApiBaseUri)
            };

            RequestSecurityTokenResponse response;
            var securityToken = trustChannelFactory.CreateChannel().Issue(requestSecurityToken, out response);

            return securityToken;
        }

        private static async void CallApi(SecurityToken securityToken)
        {
            using (var handler = new HttpClientHandler { CookieContainer = new CookieContainer() })
            {
                using (var client = new HttpClient(handler))
                {
                    handler.CookieContainer.MaxCookieSize = 8000; // Trying to make sure I can fit it in the cookie

                    var cookie = new Cookie {
                        Name = "FedAuth",
                        Value = Base64Encode(securityToken.ToTokenXmlString()),
                        HttpOnly = true,
                        Secure = true
                    };
                    handler.CookieContainer.Add(new Uri(ApiBaseUri), cookie);
                    var response = client.GetAsync(new Uri(ApiBaseUri + ApiEndPoint)).Result;
                    string result = await response.Content.ReadAsStringAsync();
                    Console.WriteLine(result);
                }
            }
        }

        public static string Base64Encode(string plainText)
        {
            var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
            return System.Convert.ToBase64String(plainTextBytes);
        }
    }
}

我不太记得我的示例基于什么代码,但如果有人能指出我正确的方向或告诉我我在哪里搞砸了,我将不胜感激。

编辑:抱歉,忘记添加我得到的内容。 Web Api 吐出一堆调试信息,因为抛出了异常,告诉我需要一个 SecurityContextToken 而不是我显然得到的 saml:Assertion。也许我的 googlefoo 不够强大,但我似乎不知道从哪里开始。我可以设置 api 以接受 SAML 断言还是需要以其他方式请求令牌?

【问题讨论】:

    标签: c# asp.net-web-api access-token adfs


    【解决方案1】:

    您不能使用 WS-Fed 调用 Web API。您需要像Calling a web API in a web app using Azure AD and OpenID Connect 一样的 OpenID Connect / OAuth。

    它适用于 Azure AD,但它确实说明了流程。

    什么版本的 ADFS?

    【讨论】:

    • 看起来 ADFS 服务器是 2.0,但很快就会升级。到目前为止,我已经应用了一些拼凑解决方案(OAuth 令牌生成和 Web api 验证),但只是为了让其他人找到这篇文章,你会建议什么作为这个问题的可接受解决方案?跨度>
    • 使用身份服务器并与 ADFS 联合。
    • 我也在尝试调用 web api,但它不是使用 wpf 应用程序调用的。调用时授权失败。如果我从控制器中删除了授权属性,它将被调用
    猜你喜欢
    • 2013-11-16
    • 2017-09-09
    • 1970-01-01
    • 1970-01-01
    • 2018-03-19
    • 2015-01-12
    • 2016-02-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多