BMC/BCS.BMC/src/BCS.BMC.Web.Core/Controllers/TokenAuthController.cs

424 lines
17 KiB
C#

using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Abp.Authorization;
using Abp.Authorization.Users;
using Abp.MultiTenancy;
using Abp.Runtime.Security;
using Abp.UI;
using BCS.BMC.Authentication.External;
using BCS.BMC.Authentication.JwtBearer;
using BCS.BMC.Authorization;
using BCS.BMC.Authorization.Users;
using BCS.BMC.Models.TokenAuth;
using BCS.BMC.MultiTenancy;
using BCS.BMC.CompanyMasters.Dto;
using System.Net;
using System.Net.Http;
using Newtonsoft.Json;
using System.Net.Http.Headers;
using BCS.BMC.BMC.CompanyMasters;
using Abp.Domain.Repositories;
using System.Runtime.Intrinsics.X86;
using System.Text;
using System.IO;
using Abp.AutoMapper;
using Abp.Domain.Entities;
using BCS.BMC.BMC.FirebaseCloudMessages;
namespace BCS.BMC.Controllers
{
[Route("api/[controller]/[action]")]
public class TokenAuthController : BMCControllerBase
{
private readonly LogInManager _logInManager;
private readonly ITenantCache _tenantCache;
private readonly AbpLoginResultTypeHelper _abpLoginResultTypeHelper;
private readonly TokenAuthConfiguration _configuration;
private readonly IExternalAuthConfiguration _externalAuthConfiguration;
private readonly IExternalAuthManager _externalAuthManager;
private readonly UserRegistrationManager _userRegistrationManager;
private readonly IRepository<CompanyMaster, int> _companyMaster;
private readonly IRepository<FirebaseToken, int> _firebaseToken;
ResponseMessageModel responsemessage = new ResponseMessageModel();
public TokenAuthController(
LogInManager logInManager,
ITenantCache tenantCache,
AbpLoginResultTypeHelper abpLoginResultTypeHelper,
TokenAuthConfiguration configuration,
IExternalAuthConfiguration externalAuthConfiguration,
IExternalAuthManager externalAuthManager,
UserRegistrationManager userRegistrationManager,
IRepository<CompanyMaster, int> companyMaster,
IRepository<FirebaseToken, int> firebaseToken)
{
_logInManager = logInManager;
_tenantCache = tenantCache;
_abpLoginResultTypeHelper = abpLoginResultTypeHelper;
_configuration = configuration;
_externalAuthConfiguration = externalAuthConfiguration;
_externalAuthManager = externalAuthManager;
_userRegistrationManager = userRegistrationManager;
_companyMaster = companyMaster;
_firebaseToken = firebaseToken;
}
[HttpPost]
public async Task<AuthenticateResultModel> Authenticate([FromBody] AuthenticateModel model)
{
var loginResult = await GetLoginResultAsync(
model.UserNameOrEmailAddress,
model.Password,
GetTenancyNameOrNull()
);
var accessToken = CreateAccessToken(CreateJwtClaims(loginResult.Identity));
return new AuthenticateResultModel
{
AccessToken = accessToken,
EncryptedAccessToken = GetEncryptedAccessToken(accessToken),
ExpireInSeconds = (int)_configuration.Expiration.TotalSeconds,
UserId = loginResult.User.Id
};
}
[HttpGet]
public List<ExternalLoginProviderInfoModel> GetExternalAuthenticationProviders()
{
return ObjectMapper.Map<List<ExternalLoginProviderInfoModel>>(_externalAuthConfiguration.Providers);
}
[HttpPost]
public async Task<ExternalAuthenticateResultModel> ExternalAuthenticate([FromBody] ExternalAuthenticateModel model)
{
var externalUser = await GetExternalUserInfo(model);
var loginResult = await _logInManager.LoginAsync(new UserLoginInfo(model.AuthProvider, model.ProviderKey, model.AuthProvider), GetTenancyNameOrNull());
switch (loginResult.Result)
{
case AbpLoginResultType.Success:
{
var accessToken = CreateAccessToken(CreateJwtClaims(loginResult.Identity));
return new ExternalAuthenticateResultModel
{
AccessToken = accessToken,
EncryptedAccessToken = GetEncryptedAccessToken(accessToken),
ExpireInSeconds = (int)_configuration.Expiration.TotalSeconds
};
}
case AbpLoginResultType.UnknownExternalLogin:
{
var newUser = await RegisterExternalUserAsync(externalUser);
if (!newUser.IsActive)
{
return new ExternalAuthenticateResultModel
{
WaitingForActivation = true
};
}
// Try to login again with newly registered user!
loginResult = await _logInManager.LoginAsync(new UserLoginInfo(model.AuthProvider, model.ProviderKey, model.AuthProvider), GetTenancyNameOrNull());
if (loginResult.Result != AbpLoginResultType.Success)
{
throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(
loginResult.Result,
model.ProviderKey,
GetTenancyNameOrNull()
);
}
var accessToken = CreateAccessToken(CreateJwtClaims(loginResult.Identity));
return new ExternalAuthenticateResultModel
{
AccessToken = accessToken,
EncryptedAccessToken = GetEncryptedAccessToken(accessToken),
ExpireInSeconds = (int)_configuration.Expiration.TotalSeconds
};
}
default:
{
throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(
loginResult.Result,
model.ProviderKey,
GetTenancyNameOrNull()
);
}
}
}
private async Task<User> RegisterExternalUserAsync(ExternalAuthUserInfo externalUser)
{
var user = await _userRegistrationManager.RegisterAsync(
externalUser.Name,
externalUser.Surname,
externalUser.EmailAddress,
externalUser.EmailAddress,
Authorization.Users.User.CreateRandomPassword(),
true
);
user.Logins = new List<UserLogin>
{
new UserLogin
{
LoginProvider = externalUser.Provider,
ProviderKey = externalUser.ProviderKey,
TenantId = user.TenantId
}
};
await CurrentUnitOfWork.SaveChangesAsync();
return user;
}
private async Task<ExternalAuthUserInfo> GetExternalUserInfo(ExternalAuthenticateModel model)
{
var userInfo = await _externalAuthManager.GetUserInfo(model.AuthProvider, model.ProviderAccessCode);
if (userInfo.ProviderKey != model.ProviderKey)
{
throw new UserFriendlyException(L("CouldNotValidateExternalUser"));
}
return userInfo;
}
private string GetTenancyNameOrNull()
{
if (!AbpSession.TenantId.HasValue)
{
return null;
}
return _tenantCache.GetOrNull(AbpSession.TenantId.Value)?.TenancyName;
}
private async Task<AbpLoginResult<Tenant, User>> GetLoginResultAsync(string usernameOrEmailAddress, string password, string tenancyName)
{
var loginResult = await _logInManager.LoginAsync(usernameOrEmailAddress, password, tenancyName);
switch (loginResult.Result)
{
case AbpLoginResultType.Success:
return loginResult;
default:
throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(loginResult.Result, usernameOrEmailAddress, tenancyName);
}
}
private string CreateAccessToken(IEnumerable<Claim> claims, TimeSpan? expiration = null)
{
var now = DateTime.UtcNow;
var jwtSecurityToken = new JwtSecurityToken(
issuer: _configuration.Issuer,
audience: _configuration.Audience,
claims: claims,
notBefore: now,
expires: now.Add(expiration ?? _configuration.Expiration),
signingCredentials: _configuration.SigningCredentials
);
return new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
}
private static List<Claim> CreateJwtClaims(ClaimsIdentity identity)
{
var claims = identity.Claims.ToList();
var nameIdClaim = claims.First(c => c.Type == ClaimTypes.NameIdentifier);
// Specifically add the jti (random nonce), iat (issued timestamp), and sub (subject/user) claims.
claims.AddRange(new[]
{
new Claim(JwtRegisteredClaimNames.Sub, nameIdClaim.Value),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.Now.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64)
});
return claims;
}
private string GetEncryptedAccessToken(string accessToken)
{
return SimpleStringCipher.Instance.Encrypt(accessToken);
}
[HttpPost]
public async Task<IActionResult> ValidateTenancy([FromBody] GetUrlDto input)
{
Uri uri = new Uri(input.InputUrl, UriKind.Absolute);
var domain = uri.Host;
if (string.IsNullOrWhiteSpace(input.InputUrl))
{
return BadRequest("Please Enter A Valid Url");
}
var company = await _companyMaster.FirstOrDefaultAsync(x => x.DomainName == domain);
if (company == null)
{
return BadRequest("Url Not Found");
}
var result = new
{
CompanyId = company.Id,
};
return Ok(result);
}
[HttpPost]
public async Task<IActionResult> Login([FromBody] LoginInputModel input)
{
var subDomainName = "";
var protocol = "";
if (string.IsNullOrWhiteSpace(input.CompanyUrl))
{
return BadRequest("Please Enter A Valid Url");
}
using (HttpClient client = new HttpClient())
{
Uri uri = new Uri(input.CompanyUrl);
var host = uri.Host;
protocol = uri.Scheme;
if (host.Split('.').Length > 2)
{
int lastIndex = host.LastIndexOf(".");
int index = host.LastIndexOf(".", lastIndex - 1);
var subdomain = host.Substring(0, index);
if (subdomain != "www")
{
subDomainName = subdomain;
}
}
var company = await _companyMaster.FirstOrDefaultAsync(x => x.DomainName == host);
if (company == null)
{
return BadRequest("Invalid Company Url");
}
// var baseUrl = uri + "api/BmcLogin";
var baseUrl = protocol + "://" + host + "/api/BmcLogin";
var data = new
{
usernameOrEmailAddress = input.UsernameOrEmailAddress,
password = input.Password
};
var requestJson = JsonConvert.SerializeObject(data);
var requestContent = new StringContent(requestJson.ToString());
requestContent.Headers.ContentType = new MediaTypeWithQualityHeaderValue("application/json");
HttpResponseMessage response = await client.PostAsync(baseUrl, requestContent);
if (response.IsSuccessStatusCode)
{
var responseStream = await response.Content.ReadAsStringAsync();
LoginOrRegisterResponseMessageModel result = JsonConvert.DeserializeObject<LoginOrRegisterResponseMessageModel>(responseStream);
var getTokenDetails = _firebaseToken.GetAllList().Where(x => x.HostName == host && x.UserId == int.Parse(result.result.userId)).FirstOrDefault();
if (getTokenDetails is null)
{
FirebaseToken entity = new FirebaseToken();
entity.UserId = int.Parse(result.result.userId);
entity.HostName = host;
entity.FcmToken = input.FcmToken;
await _firebaseToken.InsertAndGetIdAsync(entity);
}
if (getTokenDetails != null)
{
getTokenDetails.FcmToken = input.FcmToken;
await _firebaseToken.UpdateAsync(getTokenDetails);
}
return Ok(result);
}
else if (response.StatusCode == HttpStatusCode.InternalServerError)
{
var contents = await response.Content.ReadAsStringAsync();
ResponseMessageModel result = JsonConvert.DeserializeObject<ResponseMessageModel>(contents);
return BadRequest(result.error.message == "Login Failed" ? "Invalid Username Or Password" : result.error.message);
}
return Ok();
}
}
[HttpPost]
public async Task<IActionResult> Registration([FromBody] RegistrationInput input)
{
Uri uri = new Uri(input.CompanyUrl, UriKind.Absolute);
var domain = uri.Host;
if (string.IsNullOrWhiteSpace(input.CompanyUrl))
{
return BadRequest("Please Enter A Valid Url");
}
var company = await _companyMaster.FirstOrDefaultAsync(x => x.DomainName == domain);
if (company == null)
{
return BadRequest("Url Not Found");
}
using (HttpClient client = new HttpClient())
{
var baseUrl = input.CompanyUrl + "/api/services/bwac/employeeRegister/RegisterEmployeeAsNewUser";
var data = new
{
phoneNo = input.Phoneno,
userName = input.UserNameOrEmail,
password = input.Password
};
var requestJson = JsonConvert.SerializeObject(data);
var requestContent = new StringContent(requestJson.ToString());
requestContent.Headers.ContentType = new MediaTypeWithQualityHeaderValue("application/json");
HttpResponseMessage response = await client.PostAsync(baseUrl, requestContent);
if (response.IsSuccessStatusCode)
{
var responseStream = await response.Content.ReadAsStringAsync();
LoginOrRegisterResponseMessageModel result = JsonConvert.DeserializeObject<LoginOrRegisterResponseMessageModel>(responseStream);
return Ok(result);
}
else if (response.StatusCode == HttpStatusCode.InternalServerError)
{
var contents = await response.Content.ReadAsStringAsync();
ResponseMessageModel result = JsonConvert.DeserializeObject<ResponseMessageModel>(contents);
return BadRequest(result);
}
}
return BadRequest();
}
[HttpPost]
public async Task<IActionResult> DeleteRegisteredFcmToken([FromBody] FcmTokenDeleteInput input)
{
Uri uri = new Uri(input.HostName);
var host = uri.Host;
var getTokenDetails = _firebaseToken.GetAllList().Where(x => x.HostName == host && x.UserId == input.UserId).FirstOrDefault();
if (getTokenDetails != null)
{
FirebaseToken entity = new FirebaseToken();
getTokenDetails.FcmToken = null;
await _firebaseToken.UpdateAsync(getTokenDetails);
}
else
{
return BadRequest("logout failed");
}
return Ok("Success");
}
}
}