C# 正在创建Owin身份验证提供程序,该提供程序将自定义令牌交换为.Net身份验证Cookie

C# 正在创建Owin身份验证提供程序,该提供程序将自定义令牌交换为.Net身份验证Cookie,c#,asp.net,.net,owin,owin-middleware,C#,Asp.net,.net,Owin,Owin Middleware,我正在尝试在2.Net应用程序之间创建一个类似SSO的解决方案 .Net app 1有一个自定义令牌生成器和端点,用于验证返回用户信息的令牌 .Net应用程序2使用Owin进行保护,是一个典型的独立应用程序,用户可以使用密码和用户名直接登录 我创建了(基于和)一个自定义Owin提供程序,该提供程序将在授权标头中查找令牌,或从链接中查找作为查询参数的令牌,用户将单击.Net App 1中的链接,并在GET时向.Net App 2发送查询字符串中的令牌(我知道这是不安全的,我们最终将使用OpenID

我正在尝试在2.Net应用程序之间创建一个类似SSO的解决方案 .Net app 1有一个自定义令牌生成器和端点,用于验证返回用户信息的令牌

.Net应用程序2使用Owin进行保护,是一个典型的独立应用程序,用户可以使用密码和用户名直接登录

我创建了(基于和)一个自定义Owin提供程序,该提供程序将在授权标头中查找令牌,或从链接中查找作为查询参数的令牌,用户将单击.Net App 1中的链接,并在GET时向.Net App 2发送查询字符串中的令牌(我知道这是不安全的,我们最终将使用OpenID来实现它的价值,我们只需要将其用于演示)。我能够获得令牌验证它并创建标识和身份验证。我只是无法让提供商创建.Net Auth Cookie,以便对后续请求进行身份验证,而不会出现401错误

处理程序文件:

using Microsoft.Owin.Infrastructure;
using Microsoft.Owin.Logging;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Infrastructure;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

namespace SomeOAuth
{
// Created by the factory in the someAuthenticationMiddleware class.
class SomeAuthenticationHandler : AuthenticationHandler<SomeAuthenticationOptions>
{
    private const string HandledResponse = "HandledResponse";

    private readonly ILogger _logger;
    private readonly string _challenge;

    /// <summary>
    /// Creates a new OpenIdConnectAuthenticationHandler
    /// </summary>
    /// <param name="logger"></param>
    public SomeAuthenticationHandler(ILogger logger, string challenge)
    {
        _logger = logger;
        _challenge = challenge;
    }


    protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()
    {
        // ASP.Net Identity requires the NameIdentitifer field to be set or it won't  
        // accept the external login (AuthenticationManagerExtensions.GetExternalLoginInfo)
        string requestToken = null;
        string authorization = Request.Headers.Get("Authorization");

        if (!string.IsNullOrEmpty(authorization))
        {
            if (authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
            {
                requestToken = authorization.Substring("Bearer ".Length).Trim();
            }
        }

        if (string.IsNullOrEmpty(requestToken))
        {
            string accessTokenParam = Request.Query.Get("access_token");
            if (!string.IsNullOrEmpty(accessTokenParam))
            {
                requestToken = accessTokenParam;
            }
        }

        if (!string.IsNullOrEmpty(requestToken))
        {
            using (var client = new HttpClient())
            {
                try
                {
                    var request = new HttpRequestMessage(HttpMethod.Post, "https://testserver/API/Auth/Authenticate");
                    var s = new StringContent("{\"oauthtoken\":\"" + requestToken + "\"}", Encoding.UTF8, "application/json");
                    // var ts = s.ToString();
                    request.Content = new StringContent("{\"oauthtoken\":\"" + requestToken + "\"}", Encoding.UTF8, "application/json");

                    System.Diagnostics.Debug.WriteLine("Request:");
                    System.Diagnostics.Debug.WriteLine(request.ToString());
                    if (request.Content != null)
                    {
                        System.Diagnostics.Debug.WriteLine(await request.Content.ReadAsStringAsync());
                    }
                    System.Diagnostics.Debug.WriteLine("");

                    var response = await client.SendAsync(request);
                    if (response.StatusCode != HttpStatusCode.OK)
                    {
                        return null;
                    }

                    var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
                    var userId = payload.Value<string>("username");

                    //need to get the useid of the user as well as the name and role

                    var identity = new ClaimsIdentity("Some");
                    identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, "fakeuser", null, "Some"));
                    /*
                    identity.AddClaim(new Claim(ClaimTypes.GivenName, user.FirstName + " " + user.LastName));
                    identity.AddClaim(new Claim(ClaimTypes.Email, user.ContactInfo.Email));
                    identity.AddClaim(new Claim(ClaimTypes.Sid, user.Guid.ToString()));
                    */
                    identity.AddClaim(new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "Some"));
                    AuthenticationProperties properties = CreateProperties("fakeusername", "");
                    var ticket = new AuthenticationTicket(identity, new AuthenticationProperties());
                    return ticket;
                }
                catch (Exception e)
                {
                    Console.WriteLine("asdf e = " + e.Message);
                }
                return null;
            }
        }
        else
        {
            return null;
        }
    }

    /// <summary>
    /// Handles SignIn
    /// </summary>
    /// <returns></returns>
    protected override Task ApplyResponseChallengeAsync()
    {

        if (Response.StatusCode == 401)
        {
            AuthenticationResponseChallenge challenge = Helper.LookupChallenge(Options.AuthenticationType, Options.AuthenticationMode);
            if (challenge == null)
            {
                return null;
            }
        }

        return Task.FromResult<object>(null);
    }




    public override Task<bool> InvokeAsync()
    {
        return InvokeReplyPathAsync();
    }

    private async Task<bool> InvokeReplyPathAsync()
    {
        AuthenticationTicket ticket = await AuthenticateAsync();

        if (ticket != null)
        {
            string value;
            if (ticket.Properties.Dictionary.TryGetValue(HandledResponse, out value) && value == "true")
            {
                return true;
            }
            if (ticket.Identity != null)
            {
                Request.Context.Authentication.SignIn(ticket.Properties, ticket.Identity);
            }
            // Redirect back to the original secured resource, if any.
            if (!string.IsNullOrWhiteSpace(ticket.Properties.RedirectUri))
            {
                Response.Redirect(ticket.Properties.RedirectUri);
                return true;
            }
        }

        return false;
    }

    private static AuthenticationTicket GetHandledResponseTicket()
    {
        return new AuthenticationTicket(null, new AuthenticationProperties(new Dictionary<string, string>() { { HandledResponse, "true" } }));
    }

    public AuthenticationProperties CreateProperties(string userName, string Roles)
    {
        IDictionary<string, string> data = new Dictionary<string, string>
    {
        { "userName", userName },
        {"roles",Roles}
    };
        return new AuthenticationProperties(data);
    }

  }
}
扩展名文件:

using Microsoft.Owin.Extensions;
using Owin;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SomeOAuth
{

    public static class SomeAuthenticationExtensions
    {
        public static IAppBuilder UseSomeeAuthentication(this IAppBuilder app, SomeAuthenticationOptions options)
        {
            if (app == null)
            {
                throw new ArgumentNullException("app");
            }

            app.Use(typeof(SomeAuthenticationMiddleware), app, options);
            app.UseStageMarker(PipelineStage.Authenticate);

            return app;
        }
    }
}
启动文件

using System;
using CoreLX.Palms.VS.Web.Services;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Owin.Security.Providers.OpenID;
using Microsoft.Owin.Security.OAuth;
using Owin;
using SomeOAuth;
using CoreLX.Palms.LS.Web.Common.Models.User;

namespace CoreLX.Palms.VS.Web
{
    public partial class Startup
    {

        public void ConfigureAuth(IAppBuilder app)
        {

            app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
        app.CreatePerOwinContext<ApplicationSignInManager>    (ApplicationSignInManager.Create);

            //app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
            //{
            //    AccessTokenProvider = new SomeTokenProvider(),
            //    Provider = new SomeOAuthBearerAuthenticationProvider("access_token")
            //});

            app.UseSomeAuthentication(new SomeAuthenticationOptions("testuser", "9"));

            // Use a cookie to temp store information about a user     logging in with a third party login provider
            app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

            // Enable the application to use a cookie to store information for the signed in user
            app.UseCookieAuthentication(
                new CookieAuthenticationOptions
                {
                    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                    LoginPath = new PathString("/Account/Login"),
                    ExpireTimeSpan = new TimeSpan(0, 3, 0, 0),
                    Provider = new CookieAuthenticationProvider
                    {
                        OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                        validateInterval: TimeSpan.FromMinutes(30),
                        regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)),
                        OnApplyRedirect = ctx =>
                                {
                                // don't redirect to login page for webapi/ajax requests
                                // http://brockallen.com/2013/10/27/using-cookie-authentication-middleware-with-web-api-and-401-response-codes/
                                if (!IsWebApiRequest(ctx.Request))
                                {
                                    ctx.Response.Redirect(ctx.RedirectUri);
                                }
                            }
                    }
                });



            app.UseOpenIDAuthentication("http://me.yahoo.com/", "Yahoo");



        }


        private static bool IsWebApiRequest(IOwinRequest request)
        {
            // hack for check if it's webapi requesr
            if (request.Path.StartsWithSegments(new PathString("/api")))
            {
            return true;
            }

            // checks if it's ajax request
            IReadableStringCollection query = request.Query;
            if ((query != null) && (query["X-Requested-With"] == "XMLHttpRequest"))
            {
                return true;
            }
            IHeaderDictionary headers = request.Headers;
            return ((headers != null) && (headers["X-Requested-With"] ==     "XMLHttpRequest"));
    }
    }
}
以下是我尝试过的插件/提供程序的代码,只要没有401错误,我就没有首选项:

提供者

using Microsoft.Owin.Security.OAuth;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SomeOAuth
{
    public class SomeOAuthBearerAuthenticationProvider : IOAuthBearerAuthenticationProvider
    {
        readonly string _parameterName;
        public SomeOAuthBearerAuthenticationProvider(string parameterName)
        {
            _parameterName = parameterName;
        }
        public Task ApplyChallenge(OAuthChallengeContext context)
        {
            return Task.FromResult<object>(null);
        }

        public Task RequestToken(OAuthRequestTokenContext context)
        {
            string token = context.Token;
            if(string.IsNullOrEmpty(token) &&     !string.IsNullOrEmpty(_parameterName))
            {
                token = context.Request.Query.Get(_parameterName);
            }

            if (!string.IsNullOrEmpty(token))
            {
                context.Token = token;
            }

            return Task.FromResult<object>(null);
        }

        public Task ValidateIdentity(OAuthValidateIdentityContext context)
        {
            context.Validated();
            return Task.FromResult<object>(null);
        }
    }
}
使用Microsoft.Owin.Security.OAuth;
使用制度;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
命名空间SomeOAuth
{
公共类SomeOAuthBeareAuthenticationProvider:IOAuthBeareAuthenticationProvider
{
只读字符串_参数名称;
公共SomeOAuthBeareAuthenticationProvider(字符串参数名称)
{
_parameterName=parameterName;
}
公共任务ApplyChallenge(OAuthChallengeContext)
{
返回Task.FromResult(空);
}
公共任务请求令牌(OAuthRequestTokenContext上下文)
{
字符串标记=context.token;
if(string.IsNullOrEmpty(token)和&!string.IsNullOrEmpty(_参数名称))
{
token=context.Request.Query.Get(_parameterName);
}
如果(!string.IsNullOrEmpty(令牌))
{
context.Token=Token;
}
返回Task.FromResult(空);
}
公共任务ValidateIdentity(OAuthValidateIdentityContext上下文)
{
context.Validated();
返回Task.FromResult(空);
}
}
}
和AccessTokenProvider

using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Infrastructure;
using Newtonsoft.Json.Linq;
using System;
//using Newtonsoft.Json.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;


namespace SomeOAuth
{
    public sealed class SomeTokenProvider : AuthenticationTokenProvider
    {
        public override async Task ReceiveAsync(AuthenticationTokenReceiveContext context)
        {
            using (var client = new HttpClient())
            {
                try
                {
                    var request = new HttpRequestMessage(HttpMethod.Post, "https://someserver/API/Auth/Authenticate");
                    var s = new StringContent("{\"oauthtoken\":\"" + context.Token + "\"}", Encoding.UTF8, "application/json");
                    // var ts = s.ToString();
                    request.Content = new StringContent("{\"oauthtoken\":\"" + context.Token + "\"}", Encoding.UTF8, "application/json");

                    System.Diagnostics.Debug.WriteLine("Request:");
                    System.Diagnostics.Debug.WriteLine(request.ToString());
                    if (request.Content != null)
                    {
                        System.Diagnostics.Debug.WriteLine(await request.Content.ReadAsStringAsync());
                    }
                    System.Diagnostics.Debug.WriteLine("");

                    var response = await client.SendAsync(request);
                    if (response.StatusCode != HttpStatusCode.OK)
                    {
                        return;
                    }

                    var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
                    var userId = payload.Value<string>("username");

                    //need to get the useid of the user as well as the name and role

                    var identity = new ClaimsIdentity("Some");
                    identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, "someuser", null, "Some"));
                /*
                    identity.AddClaim(new Claim(ClaimTypes.GivenName, user.FirstName + " " + user.LastName));
                    identity.AddClaim(new Claim(ClaimTypes.Email, user.ContactInfo.Email));
                    identity.AddClaim(new Claim(ClaimTypes.Sid, user.Guid.ToString()));
                    */
                    identity.AddClaim(new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "Some"));
                    context.SetTicket(new AuthenticationTicket(identity, new AuthenticationProperties()));
                }
                catch (Exception e)
                {
                    Console.WriteLine("asdf e = " + e.Message);
                }
            }
        }
    }
}
使用Microsoft.Owin.Security;
使用Microsoft.Owin.Security.Infrastructure;
使用Newtonsoft.Json.Linq;
使用制度;
//使用Newtonsoft.Json.Linq;
Net系统;
使用System.Net.Http;
使用System.Security.Claims;
使用系统文本;
使用System.Threading.Tasks;
命名空间SomeOAuth
{
公共密封类SomeTokenProvider:AuthenticationTokenProvider
{
公共重写异步任务ReceiveAsync(AuthenticationTokenReceiveContext上下文)
{
使用(var client=new HttpClient())
{
尝试
{
var request=new-HttpRequestMessage(HttpMethod.Post)https://someserver/API/Auth/Authenticate");
var s=newstringcontent(“{\“oauthtoken\”:\”+context.Token+“\”}),Encoding.UTF8,“application/json”);
//var ts=s.ToString();
request.Content=newstringcontent(“{\“oauthtoken\”:\”+context.Token+“\”}),Encoding.UTF8,“application/json”);
System.Diagnostics.Debug.WriteLine(“请求:”);
System.Diagnostics.Debug.WriteLine(request.ToString());
if(request.Content!=null)
{
System.Diagnostics.Debug.WriteLine(wait request.Content.ReadAsStringAsync());
}
System.Diagnostics.Debug.WriteLine(“”);
var response=wait client.sendaync(请求);
if(response.StatusCode!=HttpStatusCode.OK)
{
返回;
}
var payload=JObject.Parse(wait response.Content.ReadAsStringAsync());
var userId=payload.Value(“用户名”);
//需要获取用户的useid以及名称和角色
var标识=新的索赔实体(“部分”);
AddClaim(新的ClaimTypes.NameIdentifier,“someuser”,null,“Some”);
/*
identity.AddClaim(新声明(ClaimTypes.GivenName,user.FirstName+“”+user.LastName));
identity.AddClaim(新声明(ClaimTypes.Email,user.ContactInfo.Email));
identity.AddClaim(新声明(ClaimTypes.Sid,user.Guid.ToString());
*/
identity.AddClaim(新索赔(“http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider","部分";;
SetTicket(新的AuthenticationTicket(identity,newauthenticationproperties());
}
捕获(例外e)
{
Console.WriteLine(“asdf e=“+e.Message”);
}
}
}
}
}

您以错误的顺序注册中间件。owin中间件模型通过auth中间件放置指令(
AuthenticationResponseGrant
)工作在返回到上一个中间件之前,在owin字典中。如果上一个中间件是外部cookie中间件,它将发出cookie。中有更多详细信息。因此,切换这两行:

// Use a cookie to temp store information about a user logging in with a third party login provider 
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

app.UseSomeAuthentication(new SomeAuthenticationOptions("testuser", "9"));
还有另一个问题。身份的
AuthenticationType
必须与cookie中间件中的一个相同。
UseExternalSigningOkie
方法在内部调用
app.SetDefaultSignInAsAuthenticationType
,因此当您创建新的
ClaimSidenty
时,您不应该使用
using Microsoft.Owin.Security.OAuth;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SomeOAuth
{
    public class SomeOAuthBearerAuthenticationProvider : IOAuthBearerAuthenticationProvider
    {
        readonly string _parameterName;
        public SomeOAuthBearerAuthenticationProvider(string parameterName)
        {
            _parameterName = parameterName;
        }
        public Task ApplyChallenge(OAuthChallengeContext context)
        {
            return Task.FromResult<object>(null);
        }

        public Task RequestToken(OAuthRequestTokenContext context)
        {
            string token = context.Token;
            if(string.IsNullOrEmpty(token) &&     !string.IsNullOrEmpty(_parameterName))
            {
                token = context.Request.Query.Get(_parameterName);
            }

            if (!string.IsNullOrEmpty(token))
            {
                context.Token = token;
            }

            return Task.FromResult<object>(null);
        }

        public Task ValidateIdentity(OAuthValidateIdentityContext context)
        {
            context.Validated();
            return Task.FromResult<object>(null);
        }
    }
}
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Infrastructure;
using Newtonsoft.Json.Linq;
using System;
//using Newtonsoft.Json.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;


namespace SomeOAuth
{
    public sealed class SomeTokenProvider : AuthenticationTokenProvider
    {
        public override async Task ReceiveAsync(AuthenticationTokenReceiveContext context)
        {
            using (var client = new HttpClient())
            {
                try
                {
                    var request = new HttpRequestMessage(HttpMethod.Post, "https://someserver/API/Auth/Authenticate");
                    var s = new StringContent("{\"oauthtoken\":\"" + context.Token + "\"}", Encoding.UTF8, "application/json");
                    // var ts = s.ToString();
                    request.Content = new StringContent("{\"oauthtoken\":\"" + context.Token + "\"}", Encoding.UTF8, "application/json");

                    System.Diagnostics.Debug.WriteLine("Request:");
                    System.Diagnostics.Debug.WriteLine(request.ToString());
                    if (request.Content != null)
                    {
                        System.Diagnostics.Debug.WriteLine(await request.Content.ReadAsStringAsync());
                    }
                    System.Diagnostics.Debug.WriteLine("");

                    var response = await client.SendAsync(request);
                    if (response.StatusCode != HttpStatusCode.OK)
                    {
                        return;
                    }

                    var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
                    var userId = payload.Value<string>("username");

                    //need to get the useid of the user as well as the name and role

                    var identity = new ClaimsIdentity("Some");
                    identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, "someuser", null, "Some"));
                /*
                    identity.AddClaim(new Claim(ClaimTypes.GivenName, user.FirstName + " " + user.LastName));
                    identity.AddClaim(new Claim(ClaimTypes.Email, user.ContactInfo.Email));
                    identity.AddClaim(new Claim(ClaimTypes.Sid, user.Guid.ToString()));
                    */
                    identity.AddClaim(new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "Some"));
                    context.SetTicket(new AuthenticationTicket(identity, new AuthenticationProperties()));
                }
                catch (Exception e)
                {
                    Console.WriteLine("asdf e = " + e.Message);
                }
            }
        }
    }
}
// Use a cookie to temp store information about a user logging in with a third party login provider 
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

app.UseSomeAuthentication(new SomeAuthenticationOptions("testuser", "9"));