我有一个当前使用资源所有者密码授予类型的应用程序,允许用户通过单页面应用程序登录。身份服务器与当前的Web API位于同一项目中。但是,我们希望为用户添加使用其Google帐户注册/登录的功能。目前,用户数据存储在表中并由ASP.NET Core Identity管理。
是否有办法让应用程序中的资源所有者密码授予类型可用于“本地”用户,还可以通过Google启用第三方身份验证?目前,我们使用用户名和密码访问Identity Server令牌端点,并将令牌存储在浏览器中。然后将其传递给任何需要授权的端点。在集成Google身份验证和检索Google令牌时,此相同的流程是否仍然有效?
答案 0 :(得分:1)
所有成就归功于 Behrooz Dalvandi 上的this精彩帖子。
此问题的解决方案是创建自定义授予并实现IExtensionGrantValidator。
public class GoogleGrant : IExtensionGrantValidator
{
private readonly IGoogleService _googleService;
private readonly IAccountService _accountService;
public GoogleGrant(IGoogleService googleService, IAccountService accountService)
{
_googleService = googleService;
_accountService = accountService;
}
public string GrantType
{
get
{
return "google_auth";
}
}
public async Task ValidateAsync(ExtensionGrantValidationContext context)
{
var userToken = context.Request.Raw.Get("id_token");
if (string.IsNullOrEmpty(userToken))
{
//You may want to add some claims here.
context.Result = new GrantValidationResult(TokenErrors.InvalidGrant, null);
return;
}
//Validate ID token
GoogleJsonWebSignature.Payload idTokenData = await _googleService.ParseGoogleIdToken(userToken);
if (idTokenData != null)
{
//Get user from the database.
ApplicationUser user = await _accountService.FindByEmail(idTokenData.Email);
if(user != null)
{
context.Result = new GrantValidationResult(user.Id, "google");
return;
}
else
{
return;
}
}
else
{
return;
}
}
}
在启动中配置此验证器
var builder = services.AddIdentityServer()
.AddInMemoryIdentityResources(Config.Ids)
.AddInMemoryApiResources(Config.Apis)
.AddInMemoryClients(Config.Clients)
.AddResourceOwnerValidator<CustomResourceOwnerPasswordValidator>()
.AddExtensionGrantValidator<GoogleGrant>();//Custom validator.
最后但并非最不重要的一点。 在配置文件中添加以下代码。注意“ google_auth”授权类型。
new Client
{
ClientId = "resourceownerclient",
AllowedGrantTypes = GrantTypes.ResourceOwnerPasswordAndClientCredentials.Append("google_auth").ToList(),
AccessTokenType = AccessTokenType.Jwt,
AccessTokenLifetime = 3600,
IdentityTokenLifetime = 3600,
UpdateAccessTokenClaimsOnRefresh = true,
SlidingRefreshTokenLifetime = 30,
AllowOfflineAccess = true,
RefreshTokenExpiration = TokenExpiration.Absolute,
RefreshTokenUsage = TokenUsage.OneTimeOnly,
AlwaysSendClientClaims = true,
Enabled = true,
ClientSecrets= new List<Secret> { new Secret("dataEventRecordsSecret".Sha256()) },
AllowedScopes = {
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
IdentityServerConstants.StandardScopes.OfflineAccess,
"api1"
}
}