我正在创建一个使用OAuth进行第三方身份验证的应用。我想将其与JWT一起使用,但是我使用的解决方案有问题,我会采用更为标准化的方式。
我有一个启动配置,该配置使用OAuth登录并作为我的身份验证架构:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(cfg =>
{
cfg.RequireHttpsMetadata = false;
cfg.SaveToken = true;
cfg.TokenValidationParameters = tokenValidationParameters;
})
.AddCoinbase(options => {
options.SendLimitCurrency = "USD";
options.ClientId = Configuration["Coinbase:ClientId"];
options.ClientSecret = Configuration["Coinbase:ClientSecret"];
COINBASE_SCOPES.ForEach(scope => options.Scope.Add(scope));
options.SaveTokens = true;
options.ClaimActions.MapJsonKey("urn:coinbase:avatar", "avatar_url");
});
用户登录时,他们将通过帐户控制器中的默认质询逻辑。
[HttpPost("ExternalLogin")]
[AllowAnonymous]
public IActionResult ExternalLogin(string provider, string returnUrl = null)
{
var redirectUrl = Url.Action(nameof(ExternalLoginCallback), "Account", new { returnUrl });
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
return Challenge(properties, provider);
}
在我的外部登录中,必须生成我自己的令牌非常烦人,我认为这可以通过某些默认逻辑来完成。 注意,为简单起见,省略了一些逻辑
[HttpGet("ExternalLoginCallback")]
[AllowAnonymous]
public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null)
{
var info = await _signInManager.GetExternalLoginInfoAsync();
var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false, bypassTwoFactor: true);
var user = await (result.Succeeded ?
_userManager.FindByLoginAsync(info.LoginProvider, info.ProviderKey)
: this.CreateIdentityUser(info));
var jwt = await Tokens.GenerateJwt(_jwtFactory.GenerateClaimsIdentity(user.UserName, user.Id),
_jwtFactory, _jwtOptions);
我找到了一个在线创建令牌的工厂,如下所示:
public class JwtFactory : IJwtFactory
{
//... More Code
public async Task<string> GenerateEncodedToken(string userName, ClaimsIdentity identity)
{
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, userName),
new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()),
new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(), ClaimValueTypes.Integer64),
identity.FindFirst(Constants.JwtClaimIdentifiers.Rol),
identity.FindFirst(Constants.JwtClaimIdentifiers.Id)
};
// Create the JWT security token and encode it.
var jwt = new JwtSecurityToken(
issuer: _jwtOptions.Issuer,
audience: _jwtOptions.Audience,
claims: claims,
notBefore: _jwtOptions.NotBefore,
expires: _jwtOptions.Expiration,
signingCredentials: _jwtOptions.SigningCredentials);
var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
return encodedJwt;
}
public ClaimsIdentity GenerateClaimsIdentity(string userName, string id)
{
return new ClaimsIdentity(new GenericIdentity(userName, "Token"), new[]
{
new Claim(Constants.JwtClaimIdentifiers.Id, id),
new Claim(Constants.JwtClaimIdentifiers.Rol, Constants.JwtClaims.ApiAccess)
});
}
//... More code
}
public class Tokens
{
public static async Task<string> GenerateJwt(ClaimsIdentity identity, IJwtFactory jwtFactory,
JwtIssuerOptions jwtOptions, JsonSerializerSettings serializerSettings = null)
{
serializerSettings = serializerSettings ?? new JsonSerializerSettings { Formatting = Formatting.Indented };
var id = identity.Claims.Single(c => c.Type == "id").Value;
var response = new
{
id = id,
auth_token = await jwtFactory.GenerateEncodedToken(id, identity),
expires_in = (int)jwtOptions.ValidFor.TotalSeconds
};
return JsonConvert.SerializeObject(response, serializerSettings);
}
}
这个JWTFactory似乎可以使这种逻辑通用,我想知道是否还有更多的.net stardarized方法来执行此操作,例如
services.AddSingleton<ITokenGenerator>(sp => {
var claimsMap = new ClaimsMap();
claimsMap.AddFromIdentity(JwtRegisteredClaimNames.Sub, x => x.UserName);
var tokenGenerator = new Microsoft.AspNetCore.Authentication.JWT.TokenGenerator(claimsMap);
});
基本上,我正在寻找一种更加标准化的轻量级方法来处理JWT令牌生成。我不需要像IdentityServer这样太疯狂的东西(不需要处理多个客户端)。