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

Ten*_*eim 7 c# adfs access-token asp.net-web-api

我遇到的情况是我需要访问使用ADFS进行身份验证的ASP.NET Web Api.我可以通过浏览器通过ADFS登录门户网站获取相关的FedAuth cookie,从而可靠地点击它.不幸的是,我需要从专用浏览器外部访问它,以便在移动应用中使用.该项目几乎是为工作和学校认证(内部部署)设置的标准visual studio web api模板的略微修改版本,并设置用于cookie认证.

来自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
    });
}
Run Code Online (Sandbox Code Playgroud)

我似乎无法弄清楚从哪里开始.我已尝试从ADFS请求访问令牌,并可使用相关登录信息获取不同版本的SAML断言,但它会被Web API拒绝.我误解了它应该如何工作吗?

从我的理解,它应该是这样的: 我认为它应该工作

  1. 应用程序从ADFS请求身份验证令牌
  2. 如果提供的信息正确,ADFS会向被请求者提供身份验证令牌
  3. 应用程序向Web API发出请求,并在名为FedAuth的cookie中发送令牌(默认情况下,无论如何)作为base64编码的字符串
  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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我不记得我的例子是什么代码,但是如果有人能指出我正确的方向或者告诉我在哪里搞砸了我会很感激.

编辑:对不起,忘了添加我得到的内容.Web Api呕吐出一堆调试信息,因为抛出了一个异常,告诉我一个SecurityContextToken是预期的而不是一个saml:我明显得到的断言.也许我的googlefoo不够强大,但我似乎无法弄清楚从哪里开始.我可以设置api接受SAML断言还是我需要以不同的方式请求令牌?

nzp*_*mad 6

您不能使用WS-Fed来调用Web API.您需要OpenID Connect/OAuth,就像使用Azure AD和OpenID Connect在Web应用程序调用Web API一样.

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

什么版本的ADFS?