C# 正在创建Owin身份验证提供程序,该提供程序将自定义令牌交换为.Net身份验证Cookie
我正在尝试在2.Net应用程序之间创建一个类似SSO的解决方案 .Net app 1有一个自定义令牌生成器和端点,用于验证返回用户信息的令牌 .Net应用程序2使用Owin进行保护,是一个典型的独立应用程序,用户可以使用密码和用户名直接登录 我创建了(基于和)一个自定义Owin提供程序,该提供程序将在授权标头中查找令牌,或从链接中查找作为查询参数的令牌,用户将单击.Net App 1中的链接,并在GET时向.Net App 2发送查询字符串中的令牌(我知道这是不安全的,我们最终将使用OpenID来实现它的价值,我们只需要将其用于演示)。我能够获得令牌验证它并创建标识和身份验证。我只是无法让提供商创建.Net Auth Cookie,以便对后续请求进行身份验证,而不会出现401错误 处理程序文件: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
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"));