using MyCore.Framework.Business;
using MyCore.Interfaces.DTO;
using MyCore.Interfaces.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;
namespace MyCore.Service.Services
{
///
/// Tokens service
///
public class TokensService
{
private readonly ILogger _logger;
private readonly TokensSettings _tokenSettings;
private readonly ProfileLogic _profileLogic;
private readonly SigningCredentials _signingCredentials;
///
/// Constructor
///
/// Logger
/// Tokens settings
/// Database context
/// Profile logic
/// Email client
public TokensService(ILogger logger, IOptions tokenSettings, ProfileLogic profileLogic)
{
_logger = logger;
_tokenSettings = tokenSettings.Value;
_profileLogic = profileLogic;
var key = Encoding.UTF8.GetBytes(_tokenSettings.Secret);
_signingCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature);
}
///
/// Authenticate
///
/// Email
/// Password
/// Token DTO in case of success
public TokenDTO Authenticate(string email, string password)
{
try
{
var claims = new List();
var expiration = DateTime.UtcNow.AddMinutes(_tokenSettings.AccessTokenExpiration);
// Todo nothing good here..
var profile = _profileLogic.Authenticate(email, password);
claims.Add(new Claim(ClaimTypes.Email, email));
// TODO: add refresh token support
var tokenHandler = new JwtSecurityTokenHandler();
var tokenDescriptor = new SecurityTokenDescriptor()
{
Subject = new ClaimsIdentity(claims),
Expires = expiration,
SigningCredentials = _signingCredentials
};
var token = tokenHandler.CreateToken(tokenDescriptor);
return new TokenDTO()
{
access_token = tokenHandler.WriteToken(token),
expires_in = _tokenSettings.AccessTokenExpiration * 60,
expiration = new DateTimeOffset(token.ValidTo),
token_type = "Bearer",
scope = Security.Scope
};
}
catch (UnauthorizedAccessException ex)
{
_logger?.LogError(ex, $"Authenticate error for user '{email}': unauthorized access");
throw;
}
catch (Exception ex)
{
_logger?.LogError(ex, $"Authenticate error for user '{email}': {ex.Message}");
throw;
}
}
public object GenerateToken(string username)
{
var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("%G2YZ=\tgN7fC9M$FXDt#q*a&]Z")); // Put the secret in a file or something
var claims = new Claim[] {
new Claim(ClaimTypes.Name, username),
new Claim(JwtRegisteredClaimNames.Email, "john.doe@blinkingcaret.com"),
new Claim(ClaimTypes.Role, "Admin")
};
var token = new JwtSecurityToken(
issuer: "MyCore App",
audience: "Miotecher",
claims: claims,
notBefore: DateTime.Now,
expires: DateTime.Now.AddDays(28),
signingCredentials: new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256)
);
string jwtToken = new JwtSecurityTokenHandler().WriteToken(token);
return jwtToken;
}
public static string GenerateSHA256String(string inputString)
{
SHA256 sha256 = SHA256Managed.Create();
byte[] bytes = Encoding.UTF8.GetBytes(inputString);
byte[] hash = sha256.ComputeHash(bytes);
return GetStringFromHash(hash);
}
public static string GetStringFromHash(byte[] hash)
{
StringBuilder result = new StringBuilder();
for (int i = 0; i < hash.Length; i++)
{
result.Append(hash[i].ToString("X2"));
}
return result.ToString();
}
}
}