c# - 使用 ADFS 对 ASP.NET Web Api 进行身份验证

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

我现在的情况是需要访问使用 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 请求访问 token ,并且可以使用相关的登录信息获取不同版本的 SAML 断言,但它被 Web API 拒绝了。我是否误解了它的工作原理?

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

  1. 应用从 ADFS 请求身份验证 token
  2. 如果提供的信息正确,ADFS 会为被请求者提供一个身份验证 token
  3. 应用程序向 Web API 发出请求,并将 token 作为 base64 编码字符串发送到名为 FedAuth 的 cookie 中(无论如何默认情况下)
  4. Web Api 将 token 发送到 ADFS 以确定 token 是否正确。
  5. ADFS 以某种成功消息作为响应
  6. Web Api 会根据身份验证的进行情况,通过拒绝或一段数据来响应应用。

这就是我在尝试弄清楚如何获得正确 token 时所拥有的。

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 断言,还是我需要以不同的方式请求 token ?

最佳答案

您不能使用 WS-Fed 调用 Web API。您需要 OpenID Connect/OAuth,如 Calling a web API in a web app using Azure AD and OpenID Connect .

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

什么版本的 ADFS?

关于c# - 使用 ADFS 对 ASP.NET Web Api 进行身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42251515/

相关文章:

c# - 如何在 FakeItEasy 中模拟 protected 虚拟成员?

javascript - 使用 jquery 和 web api 返回未定义的值

php - 让用户将视频从我的站点服务器上传到他们的 youtube channel

asp.net-core - IdentityServer4 - 如何从另一个 ApiResource 调用一个 ApiResource

angularjs - 将访问 token 添加到 Angular js 中的每个请求 header

c# - "Could not find schema information for the element"- 但我的架构文件确实包含该元素的信息

c# - 基于模板匹配相似图像

javascript - 初始加载和更新之间的 SignalR

javascript - Asp.NET Web API 和 SignalR Cors

c# - 将验证实现为方法还是属性?