我正在尝试通过Google验证用户身份。我正在使用带有Vue的ASP.NET Core的ABP启动模板。
这是我到目前为止所做的:
我在Web.Core中创建了一个GoogleAuthProviderApi
:
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.Google;
using Newtonsoft.Json.Linq;
namespace Mindbus.MindbooksSEO.Authentication.External.Google
{
public class GoogleAuthProviderApi : ExternalAuthProviderApiBase
{
public const string Name = "Google";
public override async Task<ExternalAuthUserInfo> GetUserInfo(string accessCode)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft ASP.NET Core OAuth middleware");
client.DefaultRequestHeaders.Accept.ParseAdd("application/json");
client.Timeout = TimeSpan.FromSeconds(30);
client.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
var request = new HttpRequestMessage(HttpMethod.Get, GoogleDefaults.UserInformationEndpoint);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessCode);
var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
return new ExternalAuthUserInfo
{
//Name = GoogleHelper.GetName(payload),
EmailAddress = GoogleHelper.GetEmail(payload),
//Surname = GoogleHelper.GetFamilyName(payload),
//ProviderKey = GoogleHelper.GetId(payload),
Provider = Name
};
}
}
}
}
我在Web.Host的AuthConfigurer.cs中注册了Google外部身份验证:
if (bool.Parse(configuration["Authentication:Google:IsEnabled"]))
{
services.AddAuthentication().AddGoogle(googleOptions =>
{
googleOptions.ClientId = configuration["Authentication:Google:ClientId"];
googleOptions.ClientSecret = configuration["Authentication:Google:ClientSecret"];
});
}
我已将设置添加到Web.Host中的appsettings.json,并在Secret Manager工具中创建了相应的机密(ClientId和ClientSecret)。
我已经强制API使用RequireHttpsAttribute
进行SSL。
我在[ProjectName] WebCoreModule.cs中注册了GoogleAuthProviderApi
:
public override void PreInitialize()
{
Configuration.DefaultNameOrConnectionString = _appConfiguration.GetConnectionString(
MindbooksSEOConsts.ConnectionStringName
);
// Use database for language management
Configuration.Modules.Zero().LanguageManagement.EnableDbLocalization();
Configuration.Modules.AbpAspNetCore()
.CreateControllersForAppServices(
typeof(MindbooksSEOApplicationModule).GetAssembly()
);
ConfigureTokenAuth();
Configuration.Modules.Zero().UserManagement.ExternalAuthenticationSources.Add<GoogleAuthProviderApi>();
}
我不知道我在这里缺少什么,也不知道到底想要什么。
我原本以为调用api / TokenAuth / GetExternalAuthenticationProviders端点至少会给我一个包含Google的列表,但是这个请求在结果中返回一个空数组。
此外,对于我来说,这种外部身份验证的范围有点不清楚,例如Google和Facebook等OAuth提供商。在我看来,您要么使用OAuth进行服务器端使用,在这种情况下,我不明白为什么要通过API公开部分内容。或者您有用于JavaScript Web应用程序的OAuth,在这种情况下,您不需要在自己的服务器上使用API端点,只需通过Web应用程序处理整个客户端。
那么,External Authenticate API端点的确切目的是什么?是否您自己的服务器充当身份验证的代理?那么您可以同时使用外部(Google)API的客户端和服务器端使用?
评论要求我补充一些说明。
#1:如果我在Postman中添加Abp.TenantId
标头,响应将保持不变:
GET /api/TokenAuth/GetExternalAuthenticationProviders HTTP/1.1
Host: localhost:44300
Accept: application/json
Abp.TenantId: 2
Cache-Control: no-cache
Postman-Token: 0cb72e57-4b9a-474d-b60d-492fa727a7a2
#2:Swagger中的控制台“欺骗”导致错误:
abp.swagger.login()
undefined
VM40:49 POST https://localhost:44300/api/TokenAuth/Authenticate 500 ()
abp.swagger.login @ VM40:49
(anonymous) @ VM84:1
abp.swagger.addAuthToken()
false
我认为GoogleAuthProviderApi
有问题。在我对所有CLR异常进行调试器中断后,我发现了以下错误:
'Mindbus.MindbooksSEO.Authentication.External.Google.GoogleAuthProviderApi' to type
'Abp.Authorization.Users.IExternalAuthenticationSource`2
[Mindbus.MindbooksSEO.MultiTenancy.Tenant,
Mindbus.MindbooksSEO.Authorization.Users.User]'.'
Configuration.Modules.Zero().UserManagement.ExternalAuthenticationSources.Add<GoogleAuthProviderApi>();
GetExternalAuthenticationProviders
在IExternalAuthConfiguration
看起来。
所以,在IExternalAuthConfiguration
的PostInitialize
方法中配置*WebHostModule
:
if (bool.Parse(configuration["Authentication:Google:IsEnabled"]))
{
var externalAuthConfiguration = IocManager.Resolve<IExternalAuthConfiguration>();
externalAuthConfiguration.Providers.Add(
new ExternalLoginProviderInfo(
GoogleAuthProviderApi.Name,
configuration["Authentication:Google:ClientId"],
configuration["Authentication:Google:ClientSecret"],
typeof(GoogleAuthProviderApi)
)
);
}
虽然上述处理社交登录提供程序的方式可能有效,但它是no longer recommended。
内置的.AddGoogle
方式:
if (bool.Parse(configuration["Authentication:Google:IsEnabled"]))
{
services.AddAuthentication().AddGoogle(googleOptions =>
{
googleOptions.ClientId = configuration["Authentication:Google:ClientId"];
googleOptions.ClientSecret = configuration["Authentication:Google:ClientSecret"];
});
}
......用于:
var result = await _signInManager.ExternalLoginSignInAsync(
info.LoginProvider,
info.ProviderKey,
isPersistent: false,
bypassTwoFactor : true
);
获得外部身份验证方案的方法是:
var schemes = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
您可以修改GetExternalAuthenticationProviders
以返回此数据。
对于那些访问这个主题并且没有找到答案的人(就像我一样)。
aspnetcore 2.2和abp 4.5.0 Facebook工作示例
* WebHostModule.cs
public override void PostInitialize()
{
var externalAuthConfiguration = IocManager.Resolve<IExternalAuthConfiguration>();
externalAuthConfiguration.Providers.Add(
new ExternalLoginProviderInfo(
FacebookAuthProvider.Name,
configuration["Authentication:Facebook:ClientId"],
configuration["Authentication:Facebook:Secret"],
typeof(FacebookAuthProvider)
)
);
}
* FacebookAuthProvider.cs
public class FacebookAuthProvider: ExternalAuthProviderApiBase
{
private static readonly HttpClient Client = new HttpClient();
public const string Name = "Facebook";
public override async Task<ExternalAuthUserInfo> GetUserInfo(string accessCode)
{
//gen app access token
var appAccessTokenResponse = await Client.GetStringAsync("https://graph.facebook.com/oauth/access_token" +
"?client_id=" + ProviderInfo.ClientId +
"&client_secret=" + ProviderInfo.ClientSecret +
"&grant_type=client_credentials");
var appAccessToken = JsonConvert.DeserializeObject<FacebookAppAccessToken>(appAccessTokenResponse);
//validate user access token
var userAccessTokenValidationResponse = await Client.GetStringAsync("https://graph.facebook.com/v3.2/debug_token" +
"?input_token="+ accessCode +
"&access_token="+ appAccessToken.AccessToken);
var userAccessTokenValidation = JsonConvert.DeserializeObject<FacebookUserAccessTokenValidation>(userAccessTokenValidationResponse);
if (!userAccessTokenValidation.Data.IsValid)
{
throw new ArgumentException("login_failure Invalid facebook token.");
}
//get userinfo
var userInfoResponse = await Client.GetStringAsync($"https://graph.facebook.com/v3.2/me?fields=id,email,first_name,last_name&access_token={accessCode}");
var userInfo = JsonConvert.DeserializeObject<FacebookUserData>(userInfoResponse);
return new ExternalAuthUserInfo
{
Name = userInfo.FirstName,
EmailAddress = userInfo.Email,
Surname=userInfo.LastName,
Provider=Name,
ProviderKey=userInfo.Id.ToString()
};
}
}
楷模
internal class FacebookUserData
{
public long Id { get; set; }
public string Email { get; set; }
public string Name { get; set; }
[JsonProperty("first_name")]
public string FirstName { get; set; }
[JsonProperty("last_name")]
public string LastName { get; set; }
public string Gender { get; set; }
public string Locale { get; set; }
public FacebookPictureData Picture { get; set; }
}
internal class FacebookPictureData
{
public FacebookPicture Data { get; set; }
}
internal class FacebookPicture
{
public int Height { get; set; }
public int Width { get; set; }
[JsonProperty("is_silhouette")]
public bool IsSilhouette { get; set; }
public string Url { get; set; }
}
internal class FacebookUserAccessTokenData
{
[JsonProperty("app_id")]
public long AppId { get; set; }
public string Type { get; set; }
public string Application { get; set; }
[JsonProperty("expires_at")]
public long ExpiresAt { get; set; }
[JsonProperty("is_valid")]
public bool IsValid { get; set; }
[JsonProperty("user_id")]
public long UserId { get; set; }
}
internal class FacebookUserAccessTokenValidation
{
public FacebookUserAccessTokenData Data { get; set; }
}
internal class FacebookAppAccessToken
{
[JsonProperty("token_type")]
public string TokenType { get; set; }
[JsonProperty("access_token")]
public string AccessToken { get; set; }
}