问题
I have an application that currently uses the resource owner password grant type to allow users to log in via a single page application. The identity server is hosted in the same project as the Web API currently. However, we would like to add the ability for a user to register / log in using their Google account. Currently, the user data is stored in tables and managed by ASP.NET Core Identity.
Is there a way to have both the resource owner password grant type available in the application for users who are 'local' but also enable third party authentication via Google? Currently, we hit the Identity Server token endpoint with a username and password and store the token in the browser. It's then passed to any endpoint that requires authorization. Would this same flow still work when integrating Google authentication and retrieving the Google token?
回答1:
All the credit goes to Behrooz Dalvandi for this amazing post.
The solution to this problem is to create a custom grant and implement 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;
}
}
}
Configure this validator in the Startup
var builder = services.AddIdentityServer()
.AddInMemoryIdentityResources(Config.Ids)
.AddInMemoryApiResources(Config.Apis)
.AddInMemoryClients(Config.Clients)
.AddResourceOwnerValidator<CustomResourceOwnerPasswordValidator>()
.AddExtensionGrantValidator<GoogleGrant>();//Custom validator.
And last but not the least. Add below code in the config file. Notice the 'google_auth' grant type.
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"
}
}
来源:https://stackoverflow.com/questions/47291734/identity-server-4-resource-owner-password-grant-and-google-authentication