Просмотр исходного кода

Added Google checking token

feature/added_google_login
Safet Purkovic 3 лет назад
Родитель
Сommit
800d60a5bd

+ 1
- 1
Diligent.WebAPI.Business/Services/Interfaces/IUserService.cs Просмотреть файл

@@ -3,7 +3,7 @@
public interface IUserService
{
Task<ServiceResponseDTO<AuthenticateResponseDto>> Authenticate(AuthenticateRequestDto model);
Task<ServiceResponseDTO<AuthenticateResponseDto>> Authenticate(string email);
Task<ServiceResponseDTO<AuthenticateResponseDto>> Authenticate(GoogleApiTokenInfo email);

Task<RefreshTokenResultDto> RefreshTokenAsync(RefreshTokenRequestDto model);


+ 57
- 4
Diligent.WebAPI.Business/Services/UserService.cs Просмотреть файл

@@ -1,4 +1,6 @@

using Newtonsoft.Json;
using System.Net;

namespace Diligent.WebAPI.Business.Services
{

@@ -30,6 +32,49 @@ namespace Diligent.WebAPI.Business.Services
await _userManager.CreateAsync(user, model.Password);
}

private const string GoogleApiTokenInfoUrl = "https://www.googleapis.com/oauth2/v3/tokeninfo?id_token={0}";
private string[] SupportedClientsIds = { "734219382849-nvnulsu7ibfl4bk3n164bgb7c1h5dgca.apps.googleusercontent.com" };
private bool IsTokenValid(string providerToken)
{
var httpClient = new HttpClient();
var requestUri = new Uri(string.Format(GoogleApiTokenInfoUrl, providerToken));

HttpResponseMessage httpResponseMessage;
try
{
httpResponseMessage = httpClient.GetAsync(requestUri).Result;
}
catch (Exception ex)
{
return false;
}

if (httpResponseMessage.StatusCode != HttpStatusCode.OK)
{
return false;
}

var response = httpResponseMessage.Content.ReadAsStringAsync().Result;
var googleApiTokenInfo = JsonConvert.DeserializeObject<GoogleApiTokenInfo>(response);

if (!SupportedClientsIds.Contains(googleApiTokenInfo.aud))
{
return false;
}

return true;
//return new
//{
// Email = googleApiTokenInfo.email,
// FirstName = googleApiTokenInfo.given_name,
// LastName = googleApiTokenInfo.family_name,
// Locale = googleApiTokenInfo.locale,
// Name = googleApiTokenInfo.name,
// ProviderUserId = googleApiTokenInfo.sub
//};

}

public async Task<ServiceResponseDTO<AuthenticateResponseDto>> Authenticate(AuthenticateRequestDto model)
{
var user = await _userManager.FindByNameAsync(model.Username);
@@ -61,9 +106,17 @@ namespace Diligent.WebAPI.Business.Services
return await GenerateToken(user);
}
public async Task<ServiceResponseDTO<AuthenticateResponseDto>> Authenticate(string email)
public async Task<ServiceResponseDTO<AuthenticateResponseDto>> Authenticate(GoogleApiTokenInfo model)
{
var user = await _userManager.FindByEmailAsync(email);
if (!IsTokenValid(JsonConvert.SerializeObject(model)))
{
return new ServiceResponseDTO<AuthenticateResponseDto>
{
IsError = true,
ErrorMessage = "Invalid Google Api Token"
};
}
var user = await _userManager.FindByEmailAsync(model.email);

// return null if user not found
if (user == null)
@@ -71,7 +124,7 @@ namespace Diligent.WebAPI.Business.Services
return new ServiceResponseDTO<AuthenticateResponseDto>
{
IsError = true,
ErrorMessage = $"User with email {email} does not exist in database"
ErrorMessage = $"User with email {model.email} does not exist in database"
};
}


+ 1
- 0
Diligent.WebAPI.Business/Usings.cs Просмотреть файл

@@ -12,6 +12,7 @@ global using Diligent.WebAPI.Contracts.DTOs.WebhookSubscription;
global using Diligent.WebAPI.Contracts.DTOs.Auth;
global using Diligent.WebAPI.Contracts.DTOs;
global using Diligent.WebAPI.Contracts.Exceptions;
global using Diligent.WebAPI.Contracts.Models;

global using Microsoft.EntityFrameworkCore;
global using Microsoft.Extensions.Options;

+ 80
- 0
Diligent.WebAPI.Contracts/Models/GoogleApiTokenInfo.cs Просмотреть файл

@@ -0,0 +1,80 @@
namespace Diligent.WebAPI.Contracts.Models
{
public class GoogleApiTokenInfo
{
/// <summary>
/// The Issuer Identifier for the Issuer of the response. Always https://accounts.google.com or accounts.google.com for Google ID tokens.
/// </summary>
public string iss { get; set; }

/// <summary>
/// Access token hash. Provides validation that the access token is tied to the identity token. If the ID token is issued with an access token in the server flow, this is always
/// included. This can be used as an alternate mechanism to protect against cross-site request forgery attacks, but if you follow Step 1 and Step 3 it is not necessary to verify the
/// access token.
/// </summary>
public string at_hash { get; set; }

/// <summary>
/// Identifies the audience that this ID token is intended for. It must be one of the OAuth 2.0 client IDs of your application.
/// </summary>
public string aud { get; set; }

/// <summary>
/// An identifier for the user, unique among all Google accounts and never reused. A Google account can have multiple emails at different points in time, but the sub value is never
/// changed. Use sub within your application as the unique-identifier key for the user.
/// </summary>
public string sub { get; set; }

/// <summary>
/// True if the user's e-mail address has been verified; otherwise false.
/// </summary>
public string email_verified { get; set; }

/// <summary>
/// The client_id of the authorized presenter. This claim is only needed when the party requesting the ID token is not the same as the audience of the ID token. This may be the
/// case at Google for hybrid apps where a web application and Android app have a different client_id but share the same project.
/// </summary>
public string azp { get; set; }

/// <summary>
/// The user's email address. This may not be unique and is not suitable for use as a primary key. Provided only if your scope included the string "email".
/// </summary>
public string email { get; set; }

/// <summary>
/// The time the ID token was issued, represented in Unix time (integer seconds).
/// </summary>
public string iat { get; set; }

/// <summary>
/// The time the ID token expires, represented in Unix time (integer seconds).
/// </summary>
public string exp { get; set; }

/// <summary>
/// The user's full name, in a displayable form. Might be provided when:
/// The request scope included the string "profile"
/// The ID token is returned from a token refresh
/// When name claims are present, you can use them to update your app's user records. Note that this claim is never guaranteed to be present.
/// </summary>
public string name { get; set; }

/// <summary>
/// The URL of the user's profile picture. Might be provided when:
/// The request scope included the string "profile"
/// The ID token is returned from a token refresh
/// When picture claims are present, you can use them to update your app's user records. Note that this claim is never guaranteed to be present.
/// </summary>
public string picture { get; set; }

public string given_name { get; set; }

public string family_name { get; set; }

public string locale { get; set; }

public string alg { get; set; }

public string kid { get; set; }
}
}

+ 5
- 4
Diligent.WebAPI.Host/Controllers/V1/UsersController.cs Просмотреть файл

@@ -20,7 +20,7 @@
}

[HttpPost]
public async Task<IActionResult> CreateUser([FromBody]CreateUserRequestDto model)
public async Task<IActionResult> CreateUser([FromBody] CreateUserRequestDto model)
{
await _userService.CreateUser(model);

@@ -63,10 +63,10 @@

return Ok();
}
[HttpGet("authenticateGoogle")]
public async Task<IActionResult> GoogleLogin(string email)
[HttpPost("authenticateGoogle")]
public async Task<IActionResult> GoogleLogin([FromBody] GoogleApiTokenInfo model)
{
var response = await _userService.Authenticate(email);
var response = await _userService.Authenticate(model);

if (response.IsError is true)
return BadRequest(new { message = response.ErrorMessage });
@@ -74,4 +74,5 @@
return Ok(response.Data);
}
}
}

+ 1
- 0
Diligent.WebAPI.Host/Usings.cs Просмотреть файл

@@ -19,6 +19,7 @@ global using Diligent.WebAPI.Contracts.DTOs.Insurer;
global using Diligent.WebAPI.Contracts.DTOs.WebhookSubscription;
global using Diligent.WebAPI.Contracts.DTOs.WebhookDefinition;
global using Diligent.WebAPI.Contracts.DTOs.Auth;
global using Diligent.WebAPI.Contracts.Models;

global using Microsoft.AspNetCore.Mvc;
global using Microsoft.AspNetCore.Mvc.Versioning;

Загрузка…
Отмена
Сохранить