gehgassi_backend/gehGassi.Web/Controllers/Api/ApiMobileAuthController.cs

228 lines
14 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Threading.Tasks;
using Asp.Versioning;
using AutoMapper;
using gehGassi.Core.Interfaces;
using gehGassi.Domain.Users;
using gehGassi.Dto;
using gehGassi.Web.Auth;
using gehGassi.Web.Helper;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
namespace gehGassi.Web.Controllers.Api
{
[ApiController]
[ApiVersion(1)]
[Route("api/mobileauth")]
[Route("api/v{v:apiVersion}/mobileauth")]
public class ApiMobileAuthController : ApiBaseController
{
private readonly ITokenService _tokenService;
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly IRefreshTokenService _refreshTokenService;
const string callbackScheme = "gehgassiapp";
public ApiMobileAuthController(IMapper mapper, IOptions<LocalizationOptions> localizationOptions, IAppUserService appUserService,
ITokenService tokenService, UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager, IRefreshTokenService refreshTokenService) : base(mapper, localizationOptions, appUserService)
{
_tokenService = tokenService;
_userManager = userManager;
_signInManager = signInManager;
_refreshTokenService = refreshTokenService;
}
[HttpGet("{scheme}")]
public async Task Get([FromRoute] string scheme)
{
try
{
var errorCode = CommunicationErrors.Undefined;
var auth = await Request.HttpContext.AuthenticateAsync(scheme);
if (!auth.Succeeded || auth?.Principal == null || !auth.Principal.Identities.Any(id => id.IsAuthenticated) || string.IsNullOrEmpty(auth.Properties.GetTokenValue("access_token")))
{
// Not authenticated, challenge
await Request.HttpContext.ChallengeAsync(scheme);
}
else
{
var email = string.Empty;
var providerKey = string.Empty;
var givenName = string.Empty;
var surname = string.Empty;
var token = string.Empty;
if (auth.Principal != null && auth.Principal.Identities != null && auth.Principal.Identities.Any())
{
var claims = auth.Principal.Identities.FirstOrDefault()?.Claims;
if (claims != null)
{
var claimsList = claims.ToList();
if (claimsList.Any())
{
email = claimsList?.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value;
providerKey = claimsList?.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value;
givenName = claimsList?.FirstOrDefault(c => c.Type == ClaimTypes.GivenName)?.Value;
surname = claimsList?.FirstOrDefault(c => c.Type == ClaimTypes.Surname)?.Value;
if (!string.IsNullOrWhiteSpace(email) && !string.IsNullOrWhiteSpace(providerKey))
{
//Umgestellt auf Providerkey, falls der Benutzer die Email-Adresse geändert hat, wenn kein externer Login vorhanden, dann mit email
var user = await _userManager.FindByLoginAsync("Google", providerKey) ?? await _userManager.FindByEmailAsync(email);
if (user != null)
{
if (await _userManager.IsLockedOutAsync(user) == false)
{
if (await _userManager.IsEmailConfirmedAsync(user))
{
if (!string.IsNullOrWhiteSpace(user.AppUserId))
{
var appUser = await AppUserService.GetAsync(user.AppUserId);
if (appUser != null)
{
if (appUser.Locked && appUser.LockedUntil < DateTimeOffset.UtcNow)
{
appUser.Locked = false;
appUser.LockedUntil = null;
await AppUserService.CommitAsync("System");
}
if (!appUser.Locked)
{
var usersClaims = new List<Claim>()
{
new Claim(ClaimTypes.Name, user.UserName),
new Claim(ClaimTypes.GivenName, user.FirstName),
new Claim(ClaimTypes.Surname, user.LastName),
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.UserData, user.Photo ?? ""),
new Claim(ClaimConstants.AppUserIdClaimType, user.AppUserId ?? ""),
};
var roles = await _userManager.GetRolesAsync(user);
foreach (var role in roles)
{
usersClaims.Add(new Claim(ClaimTypes.Role, role));
}
token = _tokenService.GenerateAccessToken(usersClaims);
await _refreshTokenService.RemoveExpiredAsync(user.Id, user.UserName);
user.LastLoginDate = DateTimeOffset.UtcNow;
await _userManager.UpdateAsync(user);
var externalLogins = await _userManager.GetLoginsAsync(user);
if (externalLogins?.FirstOrDefault(c => c.LoginProvider == "Google") == null)
{
await _userManager.AddLoginAsync(user, new UserLoginInfo("Google", providerKey, user.FullName));
}
errorCode = CommunicationErrors.None;
var responseValues = new Dictionary<string, string>
{
{ "error_code", errorCode.ToString() },
{ "access_token", token },
{ "email", email },
{ "register", false.ToString() },
{ "givenname", givenName },
{ "surname", surname },
{ "providerkey", providerKey }
};
var callBackUrl = callbackScheme + "://#" + string.Join(
"&",
responseValues.Where(kvp => !string.IsNullOrEmpty(kvp.Value) && kvp.Value != "-1")
.Select(kvp => $"{WebUtility.UrlEncode(kvp.Key)}={WebUtility.UrlEncode(kvp.Value)}"));
Request.HttpContext.Response.Redirect(callBackUrl);
return;
}
else
errorCode = CommunicationErrors.Login_LockedOut;
}
else
errorCode = CommunicationErrors.Login_Assignment_Missing;
}
else
errorCode = CommunicationErrors.Login_Assignment_Missing;
}
else
errorCode = CommunicationErrors.Login_Email_NotConfirmed;
}
else
errorCode = CommunicationErrors.Login_LockedOut;
}
else
{
//Es gibt den Benutzer nicht. Registrierungs-Variante
token = auth.Properties.GetTokenValue("access_token");
if (!string.IsNullOrEmpty(token))
{
errorCode = CommunicationErrors.None;
var responseValues = new Dictionary<string, string>
{
{ "error_code", errorCode.ToString() },
{ "access_token", token },
{ "email", email },
{ "register", true.ToString() },
{ "givenname", givenName },
{ "surname", surname },
{ "providerkey", providerKey }
};
var callBackUrl = callbackScheme + "://#" + string.Join(
"&",
responseValues.Where(kvp => !string.IsNullOrEmpty(kvp.Value) && kvp.Value != "-1")
.Select(kvp => $"{WebUtility.UrlEncode(kvp.Key)}={WebUtility.UrlEncode(kvp.Value)}"));
Request.HttpContext.Response.Redirect(callBackUrl);
return;
}
else
errorCode = CommunicationErrors.Undefined;
}
}
if(errorCode == CommunicationErrors.None)
errorCode = CommunicationErrors.Register_Email_Exists;
}
if (errorCode == CommunicationErrors.None)
errorCode = CommunicationErrors.Common_Model_Invalid;
}
if (errorCode == CommunicationErrors.None)
errorCode = CommunicationErrors.Common_Exists;
}
var errorResponseValues = new Dictionary<string, string>
{
{ "error_code", errorCode.ToString() },
{ "access_token", token },
{ "email", email },
{ "register", false.ToString() },
{ "givenname", givenName },
{ "surname", surname },
{ "providerkey", providerKey }
};
var errorCallBackUrl = callbackScheme + "://#" + string.Join(
"&",
errorResponseValues.Where(kvp => !string.IsNullOrEmpty(kvp.Value) && kvp.Value != "-1")
.Select(kvp => $"{WebUtility.UrlEncode(kvp.Key)}={WebUtility.UrlEncode(kvp.Value)}"));
Request.HttpContext.Response.Redirect(errorCallBackUrl);
}
}
catch (Exception ex)
{
Request.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
}
}
}
}