Google 使用 .NET Core API 登录 Angular 7
Google login in Angular 7 with .NET Core API
我正在尝试在我的 Angular 应用程序中实现 Google 登录。如果我尝试调用外部登录服务器 api 端点 return 405 错误代码如下:
Access to XMLHttpRequest at 'https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=...'
(redirected from 'http://localhost:5000/api/authentication/externalLogin?provider=Google'
) from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
如果我在新浏览器选项卡中调用 api/authentication/externalLogin?provider=Google
一切正常。我认为问题出在 angular 代码中。
我的 api 在 localhost:5000
上工作。 Angular 应用可在 localhost:4200
上运行。我使用 .net core 2.1 和 Angular 7
C#代码
Startup.cs
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false
};
})
.AddCookie()
.AddGoogle(options => {
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.ClientId = "xxx";
options.ClientSecret = "xxx";
options.Scope.Add("profile");
options.Events.OnCreatingTicket = (context) =>
{
context.Identity.AddClaim(new Claim("image", context.User.GetValue("image").SelectToken("url").ToString()));
return Task.CompletedTask;
};
});
AuthenticationController.cs
[HttpGet]
public IActionResult ExternalLogin(string provider)
{
var callbackUrl = Url.Action("ExternalLoginCallback");
var authenticationProperties = new AuthenticationProperties { RedirectUri = callbackUrl };
return this.Challenge(authenticationProperties, provider);
}
[HttpGet]
public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null)
{
var result = await HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);
return this.Ok(new
{
NameIdentifier = result.Principal.FindFirstValue(ClaimTypes.NameIdentifier),
Email = result.Principal.FindFirstValue(ClaimTypes.Email),
Picture = result.Principal.FindFirstValue("image")
});
}
Angular代码
login.component.html
<button (click)="googleLogIn()">Log in with Google</button>
login.component.ts
googleLogIn() {
this.authenticationService.loginWithGoogle()
.pipe(first())
.subscribe(
data => console.log(data)
);
}
authentication.service.ts
public loginWithGoogle() {
return this.http.get<any>(`${environment.api.apiUrl}${environment.api.authentication}externalLogin`,
{
params: new HttpParams().set('provider', 'Google'),
headers: new HttpHeaders()
.set('Access-Control-Allow-Headers', 'Content-Type')
.set('Access-Control-Allow-Methods', 'GET')
.set('Access-Control-Allow-Origin', '*')
})
.pipe(map(data => {
return data;
}));
}
我设想如下方案:
Angular -> 我的 API -> 重定向到 Google -> google return 用户数据到我的 api ->我的 API return JWT 令牌 -> Angular 使用令牌
你能帮我解决这个问题吗?
我遇到了类似的问题,既然你说你已经在后端设置了 CORS,Angular 没有在 API 请求中添加凭据可能是问题所在。当您在 url 栏中键入 api 端点时,浏览器会执行某些操作。您可以使用 angular 拦截器在每个请求中添加凭据。检查这个:https://angular.io/guide/http#intercepting-requests-and-responses
对于您的特定情况,这可能有效:
export class CookieInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
request = request.clone({
withCredentials: true
});
return next.handle(request);
}
}
我有几点要补充:
我检查了@Nehuen Antiman 的回答,它对我部分有效。
按照他的建议创建这样的拦截器是一种很好的做法,但是如果您只是将 "withCredentials" 标志添加到您的 service.ts:
public loginWithGoogle() {
return this.http.get<any>(`${environment.api.apiUrl}${environment.api.authentication}externalLogin`,
{
params: new HttpParams().set('provider', 'Google'),
headers: new HttpHeaders()
.set('Access-Control-Allow-Headers', 'Content-Type')
.set('Access-Control-Allow-Methods', 'GET')
.set('Access-Control-Allow-Origin', '*'),
withCredentials: true
})
.pipe(map(data => {
return data;
}));
}
还请记得将 AllowCredentials()
方法添加到您的 CorsOptions
。这是我的代码中的示例:
services.AddCors(options =>
{
options.AddPolicy(AllowedOriginsPolicy,
builder =>
{
builder.WithOrigins("http://localhost:4200")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
问题似乎是虽然服务器正在发送 302 响应(url 重定向)Angular 正在发出 XMLHttpRequest,但它不是重定向。有更多人有这个问题...
对我来说,试图拦截前端的响应以进行手动重定向或更改服务器上的响应代码(这是一个 'Challenge' 响应..)没有用。
因此,我所做的就是将 Angular window.location 更改为后端服务,以便浏览器可以管理响应并正确进行重定向。
注意:在post的结尾,我解释了一个更直接的 SPA 应用程序解决方案,无需使用 cookie 或 AspNetCore 身份验证。
完整的流程是这样的:
(1) Angular 将浏览器位置设置为 API -> (2) API 发送 302 响应 --> (3) 浏览器重定向到Google -> (4) Google returns 用户数据作为 cookie 到 API -> (5) API returns JWT 令牌 - > (6) Angular 使用令牌
1.- Angular 将浏览器位置设置为 API。当进程结束时,我们将提供程序和 returnURL 传递给我们希望 API 到 return JWT 令牌。
import { DOCUMENT } from '@angular/common';
...
constructor(@Inject(DOCUMENT) private document: Document, ...) { }
...
signInExternalLocation() {
let provider = 'provider=Google';
let returnUrl = 'returnUrl=' + this.document.location.origin + '/register/external';
this.document.location.href = APISecurityRoutes.authRoutes.signinexternal() + '?' + provider + '&' + returnUrl;
}
2.- API 发送 302 Challenge 响应。 我们使用提供商和 URL 我们想要的地方创建重定向 Google给我们回电话。
// GET: api/auth/signinexternal
[HttpGet("signinexternal")]
public IActionResult SigninExternal(string provider, string returnUrl)
{
// Request a redirect to the external login provider.
string redirectUrl = Url.Action(nameof(SigninExternalCallback), "Auth", new { returnUrl });
AuthenticationProperties properties = _signInMgr.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
return Challenge(properties, provider);
}
5.- API 接收 google 用户数据和 returns JWT 令牌。 在查询字符串中我们将有 Angular return URL。在我的例子中,如果用户没有注册,我正在做一个额外的步骤来请求许可。
// GET: api/auth/signinexternalcallback
[HttpGet("signinexternalcallback")]
public async Task<IActionResult> SigninExternalCallback(string returnUrl = null, string remoteError = null)
{
//string identityExternalCookie = Request.Cookies["Identity.External"];//do we have the cookie??
ExternalLoginInfo info = await _signInMgr.GetExternalLoginInfoAsync();
if (info == null) return new RedirectResult($"{returnUrl}?error=externalsigninerror");
// Sign in the user with this external login provider if the user already has a login.
Microsoft.AspNetCore.Identity.SignInResult result =
await _signInMgr.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false, bypassTwoFactor: true);
if (result.Succeeded)
{
CredentialsDTO credentials = _authService.ExternalSignIn(info);
return new RedirectResult($"{returnUrl}?token={credentials.JWTToken}");
}
if (result.IsLockedOut)
{
return new RedirectResult($"{returnUrl}?error=lockout");
}
else
{
// If the user does not have an account, then ask the user to create an account.
string loginprovider = info.LoginProvider;
string email = info.Principal.FindFirstValue(ClaimTypes.Email);
string name = info.Principal.FindFirstValue(ClaimTypes.GivenName);
string surname = info.Principal.FindFirstValue(ClaimTypes.Surname);
return new RedirectResult($"{returnUrl}?error=notregistered&provider={loginprovider}" +
$"&email={email}&name={name}&surname={surname}");
}
}
API 用于注册额外步骤(对于此调用 Angular 必须使用 'WithCredentials' 发出请求才能接收饼干):
[HttpPost("registerexternaluser")]
public async Task<IActionResult> ExternalUserRegistration([FromBody] RegistrationUserDTO registrationUser)
{
//string identityExternalCookie = Request.Cookies["Identity.External"];//do we have the cookie??
if (ModelState.IsValid)
{
// Get the information about the user from the external login provider
ExternalLoginInfo info = await _signInMgr.GetExternalLoginInfoAsync();
if (info == null) return BadRequest("Error registering external user.");
CredentialsDTO credentials = await _authService.RegisterExternalUser(registrationUser, info);
return Ok(credentials);
}
return BadRequest();
}
SPA 应用程序的不同方法:
当我完成它的工作时,我发现对于 SPA 应用程序有更好的方法 (https://developers.google.com/identity/sign-in/web/server-side-flow, , https://medium.com/mickeysden/react-and-google-oauth-with-net-core-backend-4faaba25ead0 )
对于这种方法,流程是:
(1)Angular开启google认证->(2)用户认证-->(3)Google发送googleToken到 angular -> (4) Angular 将它发送到 API -> (5) API 根据 google 和 return 验证它JWT 令牌 -> (6) Angular 使用令牌
为此,我们需要在 Angular 和 ' 中安装 'angularx-social-login' npm 包Google.Apis.Auth' netcore后端的NuGet包
1.和 4. - Angular 打开 google 身份验证 。我们将使用 angularx-social-login 库。用户在 Angular 中唱歌后将 google 令牌发送到 API.
在 login.module.ts 我们添加:
let config = new AuthServiceConfig([
{
id: GoogleLoginProvider.PROVIDER_ID,
provider: new GoogleLoginProvider('Google ClientId here!!')
}
]);
export function provideConfig() {
return config;
}
@NgModule({
declarations: [
...
],
imports: [
...
],
exports: [
...
],
providers: [
{
provide: AuthServiceConfig,
useFactory: provideConfig
}
]
})
我们的 login.component.ts:
import { AuthService, GoogleLoginProvider } from 'angularx-social-login';
...
constructor(..., private socialAuthService: AuthService)
...
signinWithGoogle() {
let socialPlatformProvider = GoogleLoginProvider.PROVIDER_ID;
this.isLoading = true;
this.socialAuthService.signIn(socialPlatformProvider)
.then((userData) => {
//on success
//this will return user data from google. What you need is a user token which you will send it to the server
this.authenticationService.googleSignInExternal(userData.idToken)
.pipe(finalize(() => this.isLoading = false)).subscribe(result => {
console.log('externallogin: ' + JSON.stringify(result));
if (!(result instanceof SimpleError) && this.credentialsService.isAuthenticated()) {
this.router.navigate(['/index']);
}
});
});
}
我们的authentication.service.ts:
googleSignInExternal(googleTokenId: string): Observable<SimpleError | ICredentials> {
return this.httpClient.get(APISecurityRoutes.authRoutes.googlesigninexternal(), {
params: new HttpParams().set('googleTokenId', googleTokenId)
})
.pipe(
map((result: ICredentials | SimpleError) => {
if (!(result instanceof SimpleError)) {
this.credentialsService.setCredentials(result, true);
}
return result;
}),
catchError(() => of(new SimpleError('error_signin')))
);
}
5.- API 根据 google 和 return 的 JWT 令牌 对其进行验证。我们将使用 'Google.Apis.Auth' NuGet 包。我不会为此提供完整的代码,但请确保在验证令牌时将观众添加到安全登录的设置中:
private async Task<GoogleJsonWebSignature.Payload> ValidateGoogleToken(string googleTokenId)
{
GoogleJsonWebSignature.ValidationSettings settings = new GoogleJsonWebSignature.ValidationSettings();
settings.Audience = new List<string>() { "Google ClientId here!!" };
GoogleJsonWebSignature.Payload payload = await GoogleJsonWebSignature.ValidateAsync(googleTokenId, settings);
return payload;
}
只是想澄清一下 Jevi 的回答中的第 5 部分,因为我花了一些时间才弄清楚如何使用 access_code 获得 google access_token。这是一个完整的服务器方法。 redirectUrl 应该等于 'Authorized JavaScript origins' 来自 Google 控制台 API 的一个。 'Authorized redirect URIs'可以为空。
[HttpPost("ValidateGoogleToken")]
public async Task<GoogleJsonWebSignature.Payload> ValidateGoogleToken(string code)
{
IConfigurationSection googleAuthSection = _configuration.GetSection("Authentication:Google");
var flow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = googleAuthSection["ClientId"],
ClientSecret = googleAuthSection["ClientSecret"]
}
});
var redirectUrl = "http://localhost:6700";
var response = await flow.ExchangeCodeForTokenAsync(string.Empty, code, redirectUrl, CancellationToken.None);
GoogleJsonWebSignature.ValidationSettings settings = new GoogleJsonWebSignature.ValidationSettings
{
Audience = new List<string>() {googleAuthSection["ClientId"]}
};
var payload = await GoogleJsonWebSignature.ValidateAsync(response.IdToken, settings);
return payload;
}
我想这会对你们有所帮助。
import { Injectable, Inject } from '@angular/core';
import { DOCUMENT } from '@angular/common';
@Injectable()
export class LoginService {
constructor(@Inject(DOCUMENT) private document: Document,...)
login() {
this.document.location.href = 'https://www.mywebsite.com/account/signInWithGoogle';
}
}
我正在尝试在我的 Angular 应用程序中实现 Google 登录。如果我尝试调用外部登录服务器 api 端点 return 405 错误代码如下:
Access to XMLHttpRequest at
'https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=...'
(redirected from'http://localhost:5000/api/authentication/externalLogin?provider=Google'
) from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
如果我在新浏览器选项卡中调用 api/authentication/externalLogin?provider=Google
一切正常。我认为问题出在 angular 代码中。
我的 api 在 localhost:5000
上工作。 Angular 应用可在 localhost:4200
上运行。我使用 .net core 2.1 和 Angular 7
C#代码
Startup.cs
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false
};
})
.AddCookie()
.AddGoogle(options => {
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.ClientId = "xxx";
options.ClientSecret = "xxx";
options.Scope.Add("profile");
options.Events.OnCreatingTicket = (context) =>
{
context.Identity.AddClaim(new Claim("image", context.User.GetValue("image").SelectToken("url").ToString()));
return Task.CompletedTask;
};
});
AuthenticationController.cs
[HttpGet]
public IActionResult ExternalLogin(string provider)
{
var callbackUrl = Url.Action("ExternalLoginCallback");
var authenticationProperties = new AuthenticationProperties { RedirectUri = callbackUrl };
return this.Challenge(authenticationProperties, provider);
}
[HttpGet]
public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null)
{
var result = await HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);
return this.Ok(new
{
NameIdentifier = result.Principal.FindFirstValue(ClaimTypes.NameIdentifier),
Email = result.Principal.FindFirstValue(ClaimTypes.Email),
Picture = result.Principal.FindFirstValue("image")
});
}
Angular代码
login.component.html
<button (click)="googleLogIn()">Log in with Google</button>
login.component.ts
googleLogIn() {
this.authenticationService.loginWithGoogle()
.pipe(first())
.subscribe(
data => console.log(data)
);
}
authentication.service.ts
public loginWithGoogle() {
return this.http.get<any>(`${environment.api.apiUrl}${environment.api.authentication}externalLogin`,
{
params: new HttpParams().set('provider', 'Google'),
headers: new HttpHeaders()
.set('Access-Control-Allow-Headers', 'Content-Type')
.set('Access-Control-Allow-Methods', 'GET')
.set('Access-Control-Allow-Origin', '*')
})
.pipe(map(data => {
return data;
}));
}
我设想如下方案: Angular -> 我的 API -> 重定向到 Google -> google return 用户数据到我的 api ->我的 API return JWT 令牌 -> Angular 使用令牌
你能帮我解决这个问题吗?
我遇到了类似的问题,既然你说你已经在后端设置了 CORS,Angular 没有在 API 请求中添加凭据可能是问题所在。当您在 url 栏中键入 api 端点时,浏览器会执行某些操作。您可以使用 angular 拦截器在每个请求中添加凭据。检查这个:https://angular.io/guide/http#intercepting-requests-and-responses
对于您的特定情况,这可能有效:
export class CookieInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
request = request.clone({
withCredentials: true
});
return next.handle(request);
}
}
我有几点要补充:
我检查了@Nehuen Antiman 的回答,它对我部分有效。
按照他的建议创建这样的拦截器是一种很好的做法,但是如果您只是将 "withCredentials" 标志添加到您的 service.ts:
public loginWithGoogle() { return this.http.get<any>(`${environment.api.apiUrl}${environment.api.authentication}externalLogin`, { params: new HttpParams().set('provider', 'Google'), headers: new HttpHeaders() .set('Access-Control-Allow-Headers', 'Content-Type') .set('Access-Control-Allow-Methods', 'GET') .set('Access-Control-Allow-Origin', '*'), withCredentials: true }) .pipe(map(data => { return data; })); }
还请记得将
AllowCredentials()
方法添加到您的CorsOptions
。这是我的代码中的示例:services.AddCors(options => { options.AddPolicy(AllowedOriginsPolicy, builder => { builder.WithOrigins("http://localhost:4200") .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials(); }); });
问题似乎是虽然服务器正在发送 302 响应(url 重定向)Angular 正在发出 XMLHttpRequest,但它不是重定向。有更多人有这个问题...
对我来说,试图拦截前端的响应以进行手动重定向或更改服务器上的响应代码(这是一个 'Challenge' 响应..)没有用。
因此,我所做的就是将 Angular window.location 更改为后端服务,以便浏览器可以管理响应并正确进行重定向。
注意:在post的结尾,我解释了一个更直接的 SPA 应用程序解决方案,无需使用 cookie 或 AspNetCore 身份验证。
完整的流程是这样的:
(1) Angular 将浏览器位置设置为 API -> (2) API 发送 302 响应 --> (3) 浏览器重定向到Google -> (4) Google returns 用户数据作为 cookie 到 API -> (5) API returns JWT 令牌 - > (6) Angular 使用令牌
1.- Angular 将浏览器位置设置为 API。当进程结束时,我们将提供程序和 returnURL 传递给我们希望 API 到 return JWT 令牌。
import { DOCUMENT } from '@angular/common';
...
constructor(@Inject(DOCUMENT) private document: Document, ...) { }
...
signInExternalLocation() {
let provider = 'provider=Google';
let returnUrl = 'returnUrl=' + this.document.location.origin + '/register/external';
this.document.location.href = APISecurityRoutes.authRoutes.signinexternal() + '?' + provider + '&' + returnUrl;
}
2.- API 发送 302 Challenge 响应。 我们使用提供商和 URL 我们想要的地方创建重定向 Google给我们回电话。
// GET: api/auth/signinexternal
[HttpGet("signinexternal")]
public IActionResult SigninExternal(string provider, string returnUrl)
{
// Request a redirect to the external login provider.
string redirectUrl = Url.Action(nameof(SigninExternalCallback), "Auth", new { returnUrl });
AuthenticationProperties properties = _signInMgr.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
return Challenge(properties, provider);
}
5.- API 接收 google 用户数据和 returns JWT 令牌。 在查询字符串中我们将有 Angular return URL。在我的例子中,如果用户没有注册,我正在做一个额外的步骤来请求许可。
// GET: api/auth/signinexternalcallback
[HttpGet("signinexternalcallback")]
public async Task<IActionResult> SigninExternalCallback(string returnUrl = null, string remoteError = null)
{
//string identityExternalCookie = Request.Cookies["Identity.External"];//do we have the cookie??
ExternalLoginInfo info = await _signInMgr.GetExternalLoginInfoAsync();
if (info == null) return new RedirectResult($"{returnUrl}?error=externalsigninerror");
// Sign in the user with this external login provider if the user already has a login.
Microsoft.AspNetCore.Identity.SignInResult result =
await _signInMgr.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false, bypassTwoFactor: true);
if (result.Succeeded)
{
CredentialsDTO credentials = _authService.ExternalSignIn(info);
return new RedirectResult($"{returnUrl}?token={credentials.JWTToken}");
}
if (result.IsLockedOut)
{
return new RedirectResult($"{returnUrl}?error=lockout");
}
else
{
// If the user does not have an account, then ask the user to create an account.
string loginprovider = info.LoginProvider;
string email = info.Principal.FindFirstValue(ClaimTypes.Email);
string name = info.Principal.FindFirstValue(ClaimTypes.GivenName);
string surname = info.Principal.FindFirstValue(ClaimTypes.Surname);
return new RedirectResult($"{returnUrl}?error=notregistered&provider={loginprovider}" +
$"&email={email}&name={name}&surname={surname}");
}
}
API 用于注册额外步骤(对于此调用 Angular 必须使用 'WithCredentials' 发出请求才能接收饼干):
[HttpPost("registerexternaluser")]
public async Task<IActionResult> ExternalUserRegistration([FromBody] RegistrationUserDTO registrationUser)
{
//string identityExternalCookie = Request.Cookies["Identity.External"];//do we have the cookie??
if (ModelState.IsValid)
{
// Get the information about the user from the external login provider
ExternalLoginInfo info = await _signInMgr.GetExternalLoginInfoAsync();
if (info == null) return BadRequest("Error registering external user.");
CredentialsDTO credentials = await _authService.RegisterExternalUser(registrationUser, info);
return Ok(credentials);
}
return BadRequest();
}
SPA 应用程序的不同方法:
当我完成它的工作时,我发现对于 SPA 应用程序有更好的方法 (https://developers.google.com/identity/sign-in/web/server-side-flow,
对于这种方法,流程是:
(1)Angular开启google认证->(2)用户认证-->(3)Google发送googleToken到 angular -> (4) Angular 将它发送到 API -> (5) API 根据 google 和 return 验证它JWT 令牌 -> (6) Angular 使用令牌
为此,我们需要在 Angular 和 ' 中安装 'angularx-social-login' npm 包Google.Apis.Auth' netcore后端的NuGet包
1.和 4. - Angular 打开 google 身份验证 。我们将使用 angularx-social-login 库。用户在 Angular 中唱歌后将 google 令牌发送到 API.
在 login.module.ts 我们添加:
let config = new AuthServiceConfig([
{
id: GoogleLoginProvider.PROVIDER_ID,
provider: new GoogleLoginProvider('Google ClientId here!!')
}
]);
export function provideConfig() {
return config;
}
@NgModule({
declarations: [
...
],
imports: [
...
],
exports: [
...
],
providers: [
{
provide: AuthServiceConfig,
useFactory: provideConfig
}
]
})
我们的 login.component.ts:
import { AuthService, GoogleLoginProvider } from 'angularx-social-login';
...
constructor(..., private socialAuthService: AuthService)
...
signinWithGoogle() {
let socialPlatformProvider = GoogleLoginProvider.PROVIDER_ID;
this.isLoading = true;
this.socialAuthService.signIn(socialPlatformProvider)
.then((userData) => {
//on success
//this will return user data from google. What you need is a user token which you will send it to the server
this.authenticationService.googleSignInExternal(userData.idToken)
.pipe(finalize(() => this.isLoading = false)).subscribe(result => {
console.log('externallogin: ' + JSON.stringify(result));
if (!(result instanceof SimpleError) && this.credentialsService.isAuthenticated()) {
this.router.navigate(['/index']);
}
});
});
}
我们的authentication.service.ts:
googleSignInExternal(googleTokenId: string): Observable<SimpleError | ICredentials> {
return this.httpClient.get(APISecurityRoutes.authRoutes.googlesigninexternal(), {
params: new HttpParams().set('googleTokenId', googleTokenId)
})
.pipe(
map((result: ICredentials | SimpleError) => {
if (!(result instanceof SimpleError)) {
this.credentialsService.setCredentials(result, true);
}
return result;
}),
catchError(() => of(new SimpleError('error_signin')))
);
}
5.- API 根据 google 和 return 的 JWT 令牌 对其进行验证。我们将使用 'Google.Apis.Auth' NuGet 包。我不会为此提供完整的代码,但请确保在验证令牌时将观众添加到安全登录的设置中:
private async Task<GoogleJsonWebSignature.Payload> ValidateGoogleToken(string googleTokenId)
{
GoogleJsonWebSignature.ValidationSettings settings = new GoogleJsonWebSignature.ValidationSettings();
settings.Audience = new List<string>() { "Google ClientId here!!" };
GoogleJsonWebSignature.Payload payload = await GoogleJsonWebSignature.ValidateAsync(googleTokenId, settings);
return payload;
}
只是想澄清一下 Jevi 的回答中的第 5 部分,因为我花了一些时间才弄清楚如何使用 access_code 获得 google access_token。这是一个完整的服务器方法。 redirectUrl 应该等于 'Authorized JavaScript origins' 来自 Google 控制台 API 的一个。 'Authorized redirect URIs'可以为空。
[HttpPost("ValidateGoogleToken")]
public async Task<GoogleJsonWebSignature.Payload> ValidateGoogleToken(string code)
{
IConfigurationSection googleAuthSection = _configuration.GetSection("Authentication:Google");
var flow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = googleAuthSection["ClientId"],
ClientSecret = googleAuthSection["ClientSecret"]
}
});
var redirectUrl = "http://localhost:6700";
var response = await flow.ExchangeCodeForTokenAsync(string.Empty, code, redirectUrl, CancellationToken.None);
GoogleJsonWebSignature.ValidationSettings settings = new GoogleJsonWebSignature.ValidationSettings
{
Audience = new List<string>() {googleAuthSection["ClientId"]}
};
var payload = await GoogleJsonWebSignature.ValidateAsync(response.IdToken, settings);
return payload;
}
我想这会对你们有所帮助。
import { Injectable, Inject } from '@angular/core';
import { DOCUMENT } from '@angular/common';
@Injectable()
export class LoginService {
constructor(@Inject(DOCUMENT) private document: Document,...)
login() {
this.document.location.href = 'https://www.mywebsite.com/account/signInWithGoogle';
}
}