我在.NET Framework中有一个应用程序,其中实现了OAuthAuthorizationServer
。现在,我想将我的应用程序升级到.NET Core 2.1,因此我进行了一些研发,并决定使用ASOS。现在的问题是我已经实现了ASOS,并且工作正常,但是我有一些无法弄清楚如何转换的块。
private Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var identity = new ClaimsIdentity(new GenericIdentity(context.UserName, OAuthDefaults.AuthenticationType),
context.Scope.Select(x => new Claim("claim", x)));
context.Validated(identity);
return Task.FromResult(0);
}
private Task GrantClientCredetails(OAuthGrantClientCredentialsContext context)
{
var identity = new ClaimsIdentity(new GenericIdentity(context.ClientId, OAuthDefaults.AuthenticationType),
context.Scope.Select(x => new Claim("claim", x)));
context.Validated(identity);
return Task.FromResult(0);
}
private readonly ConcurrentDictionary<string, string> _authenticationCodes =
new ConcurrentDictionary<string, string>(StringComparer.Ordinal);
private void CreateAuthenticationCode(AuthenticationTokenCreateContext context)
{
context.SetToken(Guid.NewGuid().ToString("n") + Guid.NewGuid().ToString("n"));
_authenticationCodes[context.Token] = context.SerializeTicket();
}
private void ReceiveAuthenticationCode(AuthenticationTokenReceiveContext context)
{
string value;
if (_authenticationCodes.TryRemove(context.Token, out value))
{
context.DeserializeTicket(value);
}
}
private void CreateRefreshToken(AuthenticationTokenCreateContext context)
{
context.SetToken(context.SerializeTicket());
}
private void ReceiveRefreshToken(AuthenticationTokenReceiveContext context)
{
context.DeserializeTicket(context.Token);
}
现在我有几个问题:
GrantResourceOwnerCredentials
将OAuthGrantResourceOwnerCredentialsContext
作为参数,GrantClientCredentials
将OAuthGrantClientCredentialsContext
作为参数。这两个上下文都包含在ASOS中不可用的范围。OAuthAuthorizationProvider
一样序列化和反序列化访问和刷新令牌?答案 0 :(得分:3)
客户端凭据和资源所有者密码授予类型是两种不同的授予类型,那么我们如何使用ASOS区分它们?
public override async Task HandleTokenRequest(HandleTokenRequestContext context)
{
if (context.Request.IsClientCredentialsGrantType())
{
// ...
}
else if (context.Request.IsPasswordGrantType())
{
// ...
}
else
{
throw new NotSupportedException();
}
}
GrantResourceOwnerCredentials将OAuthGrantResourceOwnerCredentialsContext作为参数,GrantClientCredetails将OAuthGrantClientCredentialsContext作为参数。这两个上下文都包含在ASOS中不可用的范围
public override async Task HandleTokenRequest(HandleTokenRequestContext context)
{
var scopes = context.Request.GetScopes();
// ...
}
如何像执行OAuthAUthorizationProvider一样对访问和刷新令牌进行序列化和反序列化?
通过使用OnSerializeAccessToken
/ OnDeserializeAccessToken
和OnSerializeRefreshToken
/ OnDeserializeRefreshToken
事件。
我们如何处理ASOS中的刷新令牌?我可以看到刷新令牌作为响应,但是我自己没有为刷新令牌编写任何逻辑。
与Katana的OAuth服务器中间件不同,ASOS提供了用于生成授权码和刷新令牌的默认逻辑。如果您想使用诸如令牌吊销之类的实现工具,则可以在我提到的事件中做到这一点。阅读AspNet.Security.OpenIdConnect.Server. Refresh tokens了解更多信息。
下面是一个示例,该示例返回GUID刷新令牌并将关联的(加密的)有效负载存储在数据库中:
using System;
using System.Security.Claims;
using System.Threading.Tasks;
using AspNet.Security.OpenIdConnect.Extensions;
using AspNet.Security.OpenIdConnect.Primitives;
using AspNet.Security.OpenIdConnect.Server;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
namespace AuthorizationServer
{
public class MyToken
{
public string Id { get; set; }
public string Payload { get; set; }
}
public class MyDbContext : DbContext
{
public MyDbContext(DbContextOptions<MyDbContext> options)
: base(options) { }
public DbSet<MyToken> Tokens { get; set; }
}
public class MyProvider : OpenIdConnectServerProvider
{
private readonly MyDbContext _database;
public MyProvider(MyDbContext database)
{
_database = database;
}
public override Task ValidateTokenRequest(ValidateTokenRequestContext context)
{
if (!context.Request.IsPasswordGrantType() && !context.Request.IsRefreshTokenGrantType())
{
context.Reject(error: OpenIdConnectConstants.Errors.UnsupportedGrantType);
}
else
{
// Don't enforce client authentication.
context.Skip();
}
return Task.CompletedTask;
}
public override async Task HandleTokenRequest(HandleTokenRequestContext context)
{
if (context.Request.IsPasswordGrantType())
{
if (context.Request.Username == "bob" && context.Request.Password == "bob")
{
var identity = new ClaimsIdentity(context.Scheme.Name);
identity.AddClaim(new Claim(OpenIdConnectConstants.Claims.Subject, "Bob"));
var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), identity.AuthenticationType);
ticket.SetScopes(OpenIdConnectConstants.Scopes.OfflineAccess);
context.Validate(ticket);
}
else
{
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidGrant,
description: "The username/password couple is invalid.");
}
}
else
{
var token = await _database.Tokens.FindAsync(context.Request.RefreshToken);
_database.Tokens.Remove(token);
await _database.SaveChangesAsync();
context.Validate(context.Ticket);
}
}
public override async Task SerializeRefreshToken(SerializeRefreshTokenContext context)
{
context.RefreshToken = Guid.NewGuid().ToString();
_database.Tokens.Add(new MyToken
{
Id = context.RefreshToken,
Payload = context.Options.RefreshTokenFormat.Protect(context.Ticket)
});
await _database.SaveChangesAsync();
}
public override async Task DeserializeRefreshToken(DeserializeRefreshTokenContext context)
{
context.HandleDeserialization();
var token = await _database.Tokens.FindAsync(context.RefreshToken);
if (token == null)
{
return;
}
context.Ticket = context.Options.RefreshTokenFormat.Unprotect(token.Payload);
}
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MyDbContext>(options =>
{
options.UseInMemoryDatabase(nameof(MyDbContext));
});
services.AddAuthentication()
.AddOpenIdConnectServer(options =>
{
options.TokenEndpointPath = "/token";
options.ProviderType = typeof(MyProvider);
options.AllowInsecureHttp = true;
})
.AddOAuthValidation();
services.AddMvc();
services.AddScoped<MyProvider>();
}
public void Configure(IApplicationBuilder app)
{
app.UseAuthentication();
app.UseMvcWithDefaultRoute();
}
}
}