没有cookie或本地凭据的外部自身身份验证
本文关键字:外部 身份验证 cookie 没有 | 更新日期: 2023-09-27 18:10:11
我正在使用angular和webapi开发一个跨平台的web应用程序。问题是当angular应用运行在cordova容器中时。为了更好地使用设备上的其他应用程序,我需要使用SSO插件。这个插件是什么导致我的问题,因为它做了一些事情。它拦截了所有的http请求,并向报头添加了一个承载令牌,这是由第三方令牌提供商生成的,所以我无法解码它,并覆盖了我在报头中设置的任何承载令牌。它似乎还能阻止cookies。
所以当你不能发送你自己的本地凭据时,这就有点棘手了。
所以我从https://coding.abel.nu/2014/06/writing-an-owin-authentication-middleware/和http://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin.Security.OAuth/OAuthBearerAuthenticationHandler.cs
开始所以我想我应该写自己的中间件来处理这个问题;我认为既然标准的oauth中间件可以在没有cookie的情况下工作,我应该不会很难让我的稍微不同的承载令牌中间件做到这一点。但事实并非如此……编写我自己的中间件…我能获得header,与外部令牌提供者验证,但我不能登录。
protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()
{
try
{
// Find token in default location
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();
}
}
.... Take the Request token call other Server, verify token...
也 public override async Task<bool> InvokeAsync()
{
var ticket = await this.AuthenticateAsync();
if(ticket != null)
{
this.Context.Authentication.SignIn(new AuthenticationProperties(), grantIdentity);
return false;
}
}
所以最终SignIn不会导致错误或任何事情,但实际上并没有登录。一旦到达带有[authorization]属性的控制器操作,就会得到401。我没有启用任何外部cookie。很有可能我走错了路,或者我把它弄得太难了。
你做得太辛苦了。
您应该更改默认的OAuthBearerAuthenticationProvider
,而不是创建您自己的承载身份验证中间件。
下面是在查询字符串中发送令牌的示例。
//in Startup class
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
Provider = new QueryStringOAuthBearerProvider(),
//your settings
});
//implementation
public class QueryStringOAuthBearerProvider : OAuthBearerAuthenticationProvider
{
private const string AccessTokenQueryKey = "access_token";
public override Task RequestToken(OAuthRequestTokenContext context)
{
//check if token found in the default location - "Authorization: Bearer <token>" header
if (string.IsNullOrEmpty(context.Token))
{
var token = context.Request.Query.Get(AccessTokenQueryKey);
if (!string.IsNullOrEmpty(token))
{
context.Token = token;
}
}
return Task.FromResult<object>(null);
}
}
所以…我想早点回答这个问题,但是我能够在不覆盖authorize属性的情况下弄清楚它。我最后查看了OWIN安全代码的源代码。诀窍在于,您确实需要2个OWIN中间件组件。一种是我所说的服务器中间件(我从自己的源代码中偷来的)。服务器中间件响应挑战和/或如果您感到疯狂,则为您生成本地凭据。这个中间件也是一个被动中间件组件。除非有人要求,否则我不会着手生成本地凭据,因为这有点离题,但如果有人认为它会有帮助,我可以更新。
public class LowCalorieAuthenticationServerHandler : AuthenticationHandler<LowCalorieAuthenticationServerOptions>
{
//Important this needs to be overriden, but just calls the base.
protected override Task<AuthenticationTicket> AuthenticateCoreAsync()
{
return Task.FromResult<AuthenticationTicket>(null);
}
/// <summary>The apply response challenge async.</summary>
/// <returns>The <see cref="Task"/>.</returns>
protected override async Task ApplyResponseChallengeAsync()
{
if (this.Response.StatusCode != 401)
{
Task.FromResult<object>(null);
return;
}
var challenge = this.Helper.LookupChallenge(
this.Options.AuthenticationType,
this.Options.AuthenticationMode);
if (challenge != null)
{
//OK in here you call the rediret to the 3rd party
//return a redirect to some endpoint
}
Task.FromResult<object>(null);
return;
}
}
注意重载AuthenticateCoreAsync()是如何返回的返回Task.FromResult(空);这是因为我们不希望这个中间件修改请求。applyresponsecchallengeasync将等待挑战并将您重定向到第三方登录。如果您想创建某种类型的本地令牌,您可以覆盖InvokeAsync方法
您需要的第二个中间件是令牌/外部凭据验证器。这将以某种方式对用户进行身份验证。对于内置于OWIN安全性中的本地承载令牌,它简单地对令牌进行反序列化,如果可以,并且令牌没有过期,它将对用户进行身份验证。因此,如果您希望使用第三方sso(例如google或其他任何东西)验证令牌,则可以在这里插入逻辑。在我的例子中,我不仅想调用第三方提供商来获取用户信息,还想检查他们的令牌是否对单点登录退出仍然有效,并防止多个会话。public class LowCalorieAuthenticationHandler : AuthenticationHandler<LowCalorieAuthenticationOptions>
{
//Going to give you the user for the request.. You Need to do 3 things here
//1. Get the user claim from teh request somehow, either froma header, request string, or cookie what ever you want
//2. validate the user with whatever user store or 3rd party SSO you want
//3. Generate a AuthenticationTicket to send to on to the request, you can use that to see if the user is valid in any Identity collection you want.
protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()
{
//Good to throw in a point of override here.. but to keep it simple-ish
string requestToken = null;
string authorization = Request.Headers.Get("Authorization");
//TOTAL FAKEOUT.. I am going to add a bearer token just so the simple sample works, but your client would have to provide this
authorization = "Bearer 1234567869";
//STEP 1
if (!string.IsNullOrEmpty(authorization) && authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
{
requestToken = authorization.Substring("Bearer ".Length).Trim();
return await FakeExternalBearer(requestToken);
}
return null;
}
private async Task<AuthenticationTicket> FakeExternalBearer(string token)
{
var authenticationType = Options.AuthenticationType;
//pretend to call extenal Resource server to get user //STEP 2
//CallExternal(token)
//Create the AuthTicket from the return.. I will fake it out
var identity = new ClaimsIdentity(
authenticationType,
ClaimsIdentity.DefaultNameClaimType,
ClaimsIdentity.DefaultRoleClaimType);
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier,"user1", null, authenticationType));
identity.AddClaim(new Claim(ClaimTypes.Name, "Jon",null, authenticationType));
var properties = new AuthenticationProperties();
properties.ExpiresUtc = DateTime.UtcNow.AddMinutes(1);
properties.IssuedUtc = DateTime.UtcNow;
var ticket = new AuthenticationTicket(identity, properties);
return ticket;
}
}
这里我们重写了AuthenticateCoreAsync,但我们现在做了一些事情。这是你的用户身份验证。这是中间件的ACTIVE部分。注意,它需要返回一个有效的AuthenticationTicket。这将在每个请求上运行,所以要注意调用的内容和频率。所以我在这里有一个非常简单的例子https://github.com/jzoss/LowCalorieOwin如果有人对更多的细节感兴趣,请问。我可以添加更多。我确实把它弄得太难了,因为现在我明白了,它很简单,但是没有很好的例子来说明如何做到这一点。