Quellcode durchsuchen

Merge branch 'feature/added_google_login' of Neca/HRCenter into BE_dev

feature/1507_applicants_BE
safet.purkovic vor 3 Jahren
Ursprung
Commit
38d823e384

+ 1
- 0
Diligent.WebAPI.Business/Services/Interfaces/IUserService.cs Datei anzeigen

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

Task<RefreshTokenResultDto> RefreshTokenAsync(RefreshTokenRequestDto model);


+ 78
- 19
Diligent.WebAPI.Business/Services/UserService.cs Datei anzeigen

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

using Newtonsoft.Json;
using System.Net;

namespace Diligent.WebAPI.Business.Services
{

@@ -30,6 +32,39 @@ 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;
}

public async Task<ServiceResponseDTO<AuthenticateResponseDto>> Authenticate(AuthenticateRequestDto model)
{
var user = await _userManager.FindByNameAsync(model.Username);
@@ -44,30 +79,12 @@ namespace Diligent.WebAPI.Business.Services
};
}

var isLocked = await _userManager.IsLockedOutAsync(user);

if (isLocked)
return new ServiceResponseDTO<AuthenticateResponseDto>
{
IsError = true,
ErrorMessage = "The account is locked out"
};

var result = await _userManager.CheckPasswordAsync(user, model.Password);

// password is not correct
if (!result)
{
await _userManager.AccessFailedAsync(user);
isLocked = await _userManager.IsLockedOutAsync(user);
if(isLocked)
return new ServiceResponseDTO<AuthenticateResponseDto>
{
IsError = true,
ErrorMessage = "The account is locked out"
};

return new ServiceResponseDTO<AuthenticateResponseDto>
{
@@ -76,6 +93,48 @@ namespace Diligent.WebAPI.Business.Services
};
}

return await GenerateToken(user);
}
public async Task<ServiceResponseDTO<AuthenticateResponseDto>> Authenticate(GoogleApiModel model)
{
if (!IsTokenValid(model.Token))
{
return new ServiceResponseDTO<AuthenticateResponseDto>
{
IsError = true,
ErrorMessage = "Invalid Google Api Token"
};
}
var user = await _userManager.FindByEmailAsync(model.User.email);

// return null if user not found
if (user == null)
{
return new ServiceResponseDTO<AuthenticateResponseDto>
{
IsError = true,
ErrorMessage = $"User with email {model.User.email} does not exist in database"
};
}

return await GenerateToken(user);
}

private async Task<ServiceResponseDTO<AuthenticateResponseDto>> GenerateToken(User user)
{
var isLocked = await _userManager.IsLockedOutAsync(user);

if (isLocked)
return new ServiceResponseDTO<AuthenticateResponseDto>
{
IsError = true,
ErrorMessage = "The account is locked out"
};



// authentication successful so generate jwt token
var token = await GenerateJwtToken(user, true);


+ 1
- 0
Diligent.WebAPI.Business/Usings.cs Datei anzeigen

@@ -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;

+ 8
- 0
Diligent.WebAPI.Contracts/Models/GoogleApiModel.cs Datei anzeigen

@@ -0,0 +1,8 @@
namespace Diligent.WebAPI.Contracts.Models
{
public class GoogleApiModel
{
public GoogleApiTokenInfo User { get; set; }
public string Token { get; set; }
}
}

+ 80
- 0
Diligent.WebAPI.Contracts/Models/GoogleApiTokenInfo.cs Datei anzeigen

@@ -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 bool? 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 int? iat { get; set; }

/// <summary>
/// The time the ID token expires, represented in Unix time (integer seconds).
/// </summary>
public int? 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; }
}
}

+ 12
- 0
Diligent.WebAPI.Host/.config/dotnet-tools.json Datei anzeigen

@@ -0,0 +1,12 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "6.0.10",
"commands": [
"dotnet-ef"
]
}
}
}

+ 12
- 1
Diligent.WebAPI.Host/Controllers/V1/UsersController.cs Datei anzeigen

@@ -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,5 +63,16 @@

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

if (response.IsError is true)
return BadRequest(new { message = response.ErrorMessage });

return Ok(response.Data);
}
}
}

+ 1
- 0
Diligent.WebAPI.Host/Diligent.WebAPI.Host.csproj.user Datei anzeigen

@@ -4,6 +4,7 @@
<Controller_SelectedScaffolderID>ApiControllerWithActionsScaffolder</Controller_SelectedScaffolderID>
<Controller_SelectedScaffolderCategoryPath>root/Common/Api</Controller_SelectedScaffolderCategoryPath>
<ActiveDebugProfile>IIS Express</ActiveDebugProfile>
<NameOfLastUsedPublishProfile>IISProfile</NameOfLastUsedPublishProfile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>

+ 26
- 0
Diligent.WebAPI.Host/Properties/PublishProfiles/IISProfile.pubxml Datei anzeigen

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<WebPublishMethod>MSDeploy</WebPublishMethod>
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<SiteUrlToLaunchAfterPublish>http://192.168.88.105:5036/</SiteUrlToLaunchAfterPublish>
<ExcludeApp_Data>false</ExcludeApp_Data>
<ProjectGuid>cba426e3-0cb5-4096-9bf2-57f8dcca785b</ProjectGuid>
<SelfContained>false</SelfContained>
<MSDeployServiceURL>http://192.168.88.105</MSDeployServiceURL>
<DeployIisAppPath>HRCenterDev</DeployIisAppPath>
<RemoteSitePhysicalPath />
<SkipExtraFilesOnServer>true</SkipExtraFilesOnServer>
<MSDeployPublishMethod>RemoteAgent</MSDeployPublishMethod>
<EnableMSDeployBackup>true</EnableMSDeployBackup>
<EnableMsDeployAppOffline>true</EnableMsDeployAppOffline>
<UserName />
<_SavePWD>false</_SavePWD>
<_TargetId>IISWebDeploy</_TargetId>
</PropertyGroup>
</Project>

+ 12
- 0
Diligent.WebAPI.Host/Properties/PublishProfiles/IISProfile.pubxml.user Datei anzeigen

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<TimeStampOfAssociatedLegacyPublishXmlFile />
<EncryptedPassword />
<History>True|2022-10-25T18:20:36.0550404Z;</History>
<LastFailureDetails />
</PropertyGroup>
</Project>

+ 1
- 0
Diligent.WebAPI.Host/Usings.cs Datei anzeigen

@@ -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;

+ 1
- 1
Diligent.WebAPI.Host/appsettings.Development.json Datei anzeigen

@@ -1,6 +1,6 @@
{
"ConnectionStrings": {
"WebApi": "Server=.;Database=HRCenter;Trusted_Connection=True;MultipleActiveResultSets=true"
"WebApi": "Server=192.168.88.105;Database=HRCenter;User Id=hrcentar;Password="
},
"Authorization": {
"JwtExpiredTime": "5",

+ 8
- 0
Diligent.WebAPI.Host/appsettings.json Datei anzeigen

@@ -1,2 +1,10 @@
{
"ConnectionStrings": {
"WebApi": "Server=192.168.88.105;Database=HRCenter;User Id=hrcentar;Password=;"
},
"Authorization": {
"JwtExpiredTime": "5",
"JwtRefreshExpiredTime": "30",
"Secret": "SECRET_ASKGFH#$_#((Y)#I%EWJGDSJTGKEOS@$SAF"
}
}

Laden…
Abbrechen
Speichern