Tuitio refactoring
parent
e5854ef76b
commit
747b91898d
|
@ -17,7 +17,7 @@
|
||||||
<Note>
|
<Note>
|
||||||
<Version>1.0.1</Version>
|
<Version>1.0.1</Version>
|
||||||
<Content>
|
<Content>
|
||||||
◾ Hard changes in token structure. Now the token format is base64 and contains a json with all user data like username, first name, last name, profile picture url, email address and a list of claims that can be configured from the database for each user independently.
|
◾ Big changes in token structure. Now the token format is base64 and contains a json with all user data like username, first name, last name, profile picture url, email address and a list of claims that can be configured from the database for each user independently.
|
||||||
◾ The generation and validation mechanism for the token has been rewritten to meet the new token structure.
|
◾ The generation and validation mechanism for the token has been rewritten to meet the new token structure.
|
||||||
◾ The complexity of user information has grown a lot. All users have now besides the data from token other information such as statuses, failed login attempts, last login date, password change date and security stamp.
|
◾ The complexity of user information has grown a lot. All users have now besides the data from token other information such as statuses, failed login attempts, last login date, password change date and security stamp.
|
||||||
◾ All tokens are persisted in the database and the active ones are reload at a server failure or in case of a restart.
|
◾ All tokens are persisted in the database and the active ones are reload at a server failure or in case of a restart.
|
||||||
|
@ -60,4 +60,12 @@
|
||||||
◾ Added README.md file
|
◾ Added README.md file
|
||||||
</Content>
|
</Content>
|
||||||
</Note>
|
</Note>
|
||||||
|
<Note>
|
||||||
|
<Version>2.1.0</Version>
|
||||||
|
<Content>
|
||||||
|
◾ Tuitio refactoring
|
||||||
|
◾ Added account logout method
|
||||||
|
◾ Tuitio performance optimizations
|
||||||
|
</Content>
|
||||||
|
</Note>
|
||||||
</ReleaseNotes>
|
</ReleaseNotes>
|
|
@ -4,7 +4,7 @@ using MediatR;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Tuitio.Application.Services;
|
using Tuitio.Application.Services.Abstractions;
|
||||||
using Tuitio.PublishedLanguage.Constants;
|
using Tuitio.PublishedLanguage.Constants;
|
||||||
using Tuitio.PublishedLanguage.Dto;
|
using Tuitio.PublishedLanguage.Dto;
|
||||||
|
|
||||||
|
@ -30,15 +30,13 @@ namespace Tuitio.Application.CommandHandlers
|
||||||
var loginResult = await _userService.Login(command.UserName, command.Password);
|
var loginResult = await _userService.Login(command.UserName, command.Password);
|
||||||
if (loginResult == null)
|
if (loginResult == null)
|
||||||
{
|
{
|
||||||
_logger.LogDebug($"Authentication failed for user '{command.UserName}'.");
|
_logger.LogDebug($"Login failed for user '{command.UserName}'.");
|
||||||
return Envelope<AccountLoginResult>.Error(EnvelopeStatus.BAD_CREDENTIALS);
|
return Envelope<AccountLoginResult>.Error(EnvelopeStatus.BAD_CREDENTIALS);
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogDebug($"Authentication succeeded for user '{command.UserName}'.");
|
_logger.LogDebug($"Login succeeded for user '{command.UserName}'.");
|
||||||
|
|
||||||
var token = new Token(loginResult.Raw, loginResult.Token.ExpiresIn);
|
var result = new AccountLoginResult(loginResult.Raw, loginResult.Token.ExpiresIn);
|
||||||
|
|
||||||
var result = new AccountLoginResult(token);
|
|
||||||
return Envelope<AccountLoginResult>.Success(result);
|
return Envelope<AccountLoginResult>.Success(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,8 @@ using MediatR;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Tuitio.Application.Services;
|
using Tuitio.Application.Services.Abstractions;
|
||||||
|
using Tuitio.PublishedLanguage.Constants;
|
||||||
using Tuitio.PublishedLanguage.Dto;
|
using Tuitio.PublishedLanguage.Dto;
|
||||||
|
|
||||||
namespace Tuitio.Application.CommandHandlers
|
namespace Tuitio.Application.CommandHandlers
|
||||||
|
@ -30,6 +31,12 @@ namespace Tuitio.Application.CommandHandlers
|
||||||
public async Task<Envelope<AccountLogoutResult>> Handle(Command command, CancellationToken cancellationToken)
|
public async Task<Envelope<AccountLogoutResult>> Handle(Command command, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var logoutResult = await _userService.Logout(command.Token);
|
var logoutResult = await _userService.Logout(command.Token);
|
||||||
|
if (logoutResult == null)
|
||||||
|
{
|
||||||
|
_logger.LogDebug($"Logout failed for token '{command.Token}'.");
|
||||||
|
return Envelope<AccountLogoutResult>.Error(EnvelopeStatus.UNAUTHENTICATED);
|
||||||
|
}
|
||||||
|
|
||||||
_logger.LogDebug($"Logout succeeded for user '{logoutResult.UserName}'.");
|
_logger.LogDebug($"Logout succeeded for user '{logoutResult.UserName}'.");
|
||||||
|
|
||||||
var result = _mapper.Map<AccountLogoutResult>(logoutResult);
|
var result = _mapper.Map<AccountLogoutResult>(logoutResult);
|
||||||
|
|
|
@ -1,46 +1,46 @@
|
||||||
// Copyright (c) 2020 Tudor Stanciu
|
// Copyright (c) 2020 Tudor Stanciu
|
||||||
|
|
||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using Tuitio.Application.Services;
|
|
||||||
using Tuitio.PublishedLanguage.Dto;
|
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Tuitio.Application.Services.Abstractions;
|
||||||
using Tuitio.PublishedLanguage.Constants;
|
using Tuitio.PublishedLanguage.Constants;
|
||||||
|
using Tuitio.PublishedLanguage.Dto;
|
||||||
|
|
||||||
namespace Tuitio.Application.CommandHandlers
|
namespace Tuitio.Application.CommandHandlers
|
||||||
{
|
{
|
||||||
public class AuthorizeTokenHandler
|
public class AuthorizationHandler
|
||||||
{
|
{
|
||||||
public record Command(string Token) : IRequest<Envelope<TokenAuthorizationResult>>;
|
public record Command(string Token) : IRequest<Envelope<AuthorizationResult>>;
|
||||||
|
|
||||||
public class CommandHandler : IRequestHandler<Command, Envelope<TokenAuthorizationResult>>
|
public class CommandHandler : IRequestHandler<Command, Envelope<AuthorizationResult>>
|
||||||
{
|
{
|
||||||
private readonly IUserService _userService;
|
private readonly IUserService _userService;
|
||||||
private readonly IMapper _mapper;
|
private readonly IMapper _mapper;
|
||||||
private readonly ILogger<AuthorizeTokenHandler> _logger;
|
private readonly ILogger<AuthorizationHandler> _logger;
|
||||||
|
|
||||||
public CommandHandler(IUserService userService, IMapper mapper, ILogger<AuthorizeTokenHandler> logger)
|
public CommandHandler(IUserService userService, IMapper mapper, ILogger<AuthorizationHandler> logger)
|
||||||
{
|
{
|
||||||
_userService = userService;
|
_userService = userService;
|
||||||
_mapper = mapper;
|
_mapper = mapper;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<Envelope<TokenAuthorizationResult>> Handle(Command command, CancellationToken cancellationToken)
|
public Task<Envelope<AuthorizationResult>> Handle(Command command, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var token = _userService.Authorize(command.Token);
|
var token = _userService.Authorize(command.Token);
|
||||||
if (token == null)
|
if (token == null)
|
||||||
{
|
{
|
||||||
_logger.LogDebug($"Authorization failed for token '{command.Token}'.");
|
_logger.LogDebug($"Authorization failed for token '{command.Token}'.");
|
||||||
var result = Envelope<TokenAuthorizationResult>.Error(EnvelopeStatus.UNAUTHORIZED);
|
var result = Envelope<AuthorizationResult>.Error(EnvelopeStatus.UNAUTHORIZED);
|
||||||
return Task.FromResult(result);
|
return Task.FromResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogDebug($"Authorization succeeded for token '{command.Token}'.");
|
_logger.LogDebug($"Authorization succeeded for token '{command.Token}'.");
|
||||||
var authorizationResult = new TokenAuthorizationResult(_mapper.Map<TokenCore>(token));
|
var authorizationResult = _mapper.Map<AuthorizationResult>(token);
|
||||||
var envelope = Envelope<TokenAuthorizationResult>.Success(authorizationResult);
|
var envelope = Envelope<AuthorizationResult>.Success(authorizationResult);
|
||||||
return Task.FromResult(envelope);
|
return Task.FromResult(envelope);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
// Copyright (c) 2020 Tudor Stanciu
|
// Copyright (c) 2020 Tudor Stanciu
|
||||||
|
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Tuitio.Application.Services;
|
using Tuitio.Application.Services;
|
||||||
using Tuitio.Application.Services.Abstractions;
|
using Tuitio.Application.Services.Abstractions;
|
||||||
using Tuitio.Application.Stores;
|
using Tuitio.Application.Stores;
|
||||||
using Tuitio.Domain.Abstractions;
|
using Tuitio.Domain.Abstractions;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
|
|
||||||
namespace Tuitio.Application
|
namespace Tuitio.Application
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace Tuitio.Application.Mappings
|
||||||
{
|
{
|
||||||
public MappingProfile()
|
public MappingProfile()
|
||||||
{
|
{
|
||||||
CreateMap<models.Token, dto.TokenCore>();
|
CreateMap<models.Token, dto.AuthorizationResult>();
|
||||||
CreateMap<AppUser, models.Token>()
|
CreateMap<AppUser, models.Token>()
|
||||||
.ForMember(z => z.Claims, src => src.MapFrom(z => ComposeClaims(z.Claims)));
|
.ForMember(z => z.Claims, src => src.MapFrom(z => ComposeClaims(z.Claims)));
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
using Tuitio.Domain.Entities;
|
using Tuitio.Domain.Entities;
|
||||||
using Tuitio.Domain.Models;
|
using Tuitio.Domain.Models;
|
||||||
|
|
||||||
namespace Tuitio.Application.Services
|
namespace Tuitio.Application.Services.Abstractions
|
||||||
{
|
{
|
||||||
internal interface ITokenService
|
internal interface ITokenService
|
||||||
{
|
{
|
|
@ -1,10 +1,10 @@
|
||||||
// Copyright (c) 2020 Tudor Stanciu
|
// Copyright (c) 2020 Tudor Stanciu
|
||||||
|
|
||||||
using Tuitio.Domain.Models;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Tuitio.Domain.Models;
|
||||||
using Tuitio.Domain.Models.Account;
|
using Tuitio.Domain.Models.Account;
|
||||||
|
|
||||||
namespace Tuitio.Application.Services
|
namespace Tuitio.Application.Services.Abstractions
|
||||||
{
|
{
|
||||||
public interface IUserService
|
public interface IUserService
|
||||||
{
|
{
|
|
@ -5,6 +5,7 @@ using Newtonsoft.Json;
|
||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using Tuitio.Application.Services.Abstractions;
|
||||||
using Tuitio.Application.Stores;
|
using Tuitio.Application.Stores;
|
||||||
using Tuitio.Domain.Abstractions;
|
using Tuitio.Domain.Abstractions;
|
||||||
using Tuitio.Domain.Entities;
|
using Tuitio.Domain.Entities;
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
// Copyright (c) 2020 Tudor Stanciu
|
// Copyright (c) 2020 Tudor Stanciu
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Tuitio.Application.Services.Abstractions;
|
using Tuitio.Application.Services.Abstractions;
|
||||||
using Tuitio.Application.Stores;
|
using Tuitio.Application.Stores;
|
||||||
using Tuitio.Domain.Abstractions;
|
using Tuitio.Domain.Abstractions;
|
||||||
using Tuitio.Domain.Entities;
|
using Tuitio.Domain.Entities;
|
||||||
using Tuitio.Domain.Models;
|
using Tuitio.Domain.Models;
|
||||||
using Tuitio.Domain.Repositories;
|
|
||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Tuitio.Domain.Models.Account;
|
using Tuitio.Domain.Models.Account;
|
||||||
|
using Tuitio.Domain.Repositories;
|
||||||
|
|
||||||
namespace Tuitio.Application.Services
|
namespace Tuitio.Application.Services
|
||||||
{
|
{
|
||||||
|
@ -33,6 +33,9 @@ namespace Tuitio.Application.Services
|
||||||
{
|
{
|
||||||
var passwordHash = _hashingService.HashSha256(password);
|
var passwordHash = _hashingService.HashSha256(password);
|
||||||
var user = await _userRepository.GetUser(userName, passwordHash);
|
var user = await _userRepository.GetUser(userName, passwordHash);
|
||||||
|
if (user == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
var valid = ValidateUser(user);
|
var valid = ValidateUser(user);
|
||||||
if (!valid)
|
if (!valid)
|
||||||
return null;
|
return null;
|
||||||
|
@ -41,8 +44,7 @@ namespace Tuitio.Application.Services
|
||||||
var raw = _tokenService.GenerateTokenRaw(token);
|
var raw = _tokenService.GenerateTokenRaw(token);
|
||||||
_securityStore.Set(raw, token);
|
_securityStore.Set(raw, token);
|
||||||
|
|
||||||
|
await _userRepository.UpdateUserAfterLogin(user, token, raw);
|
||||||
await _userRepository.UpdateUserAfterAuthentication(user, token, raw);
|
|
||||||
|
|
||||||
var result = new LoginResult(token, raw);
|
var result = new LoginResult(token, raw);
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
// Copyright (c) 2020 Tudor Stanciu
|
// Copyright (c) 2020 Tudor Stanciu
|
||||||
|
|
||||||
using Tuitio.Domain.Data.DbContexts;
|
|
||||||
using Tuitio.Domain.Entities;
|
|
||||||
using Tuitio.Domain.Models;
|
|
||||||
using Tuitio.Domain.Repositories;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Tuitio.Domain.Data.DbContexts;
|
||||||
|
using Tuitio.Domain.Entities;
|
||||||
|
using Tuitio.Domain.Models;
|
||||||
|
using Tuitio.Domain.Repositories;
|
||||||
|
|
||||||
namespace Tuitio.Domain.Data.Repositories
|
namespace Tuitio.Domain.Data.Repositories
|
||||||
{
|
{
|
||||||
|
@ -28,7 +28,7 @@ namespace Tuitio.Domain.Data.Repositories
|
||||||
.FirstOrDefaultAsync(z => z.UserName == userName && z.Password == password);
|
.FirstOrDefaultAsync(z => z.UserName == userName && z.Password == password);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UpdateUserAfterAuthentication(AppUser user, Token token, string tokenRaw)
|
public async Task UpdateUserAfterLogin(AppUser user, Token token, string tokenRaw)
|
||||||
{
|
{
|
||||||
var userToken = new UserToken()
|
var userToken = new UserToken()
|
||||||
{
|
{
|
||||||
|
@ -40,23 +40,25 @@ namespace Tuitio.Domain.Data.Repositories
|
||||||
};
|
};
|
||||||
|
|
||||||
await _dbContext.AddAsync(userToken);
|
await _dbContext.AddAsync(userToken);
|
||||||
|
|
||||||
user.LastLoginDate = DateTime.UtcNow;
|
user.LastLoginDate = DateTime.UtcNow;
|
||||||
|
|
||||||
//asta nu trebuie
|
|
||||||
//_dbContext.Update(user);
|
|
||||||
|
|
||||||
await _dbContext.SaveChangesAsync();
|
await _dbContext.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<UserToken[]> GetActiveTokens()
|
public async Task<UserToken[]> GetActiveTokens()
|
||||||
{
|
{
|
||||||
var currentDate = DateTime.UtcNow;
|
var currentDate = DateTime.UtcNow;
|
||||||
|
|
||||||
|
// remove expired tokens
|
||||||
|
_dbContext.UserTokens.RemoveRange(_dbContext.UserTokens.Where(z => z.ValidUntil < currentDate));
|
||||||
|
await _dbContext.SaveChangesAsync();
|
||||||
|
|
||||||
|
// retrieve active tokens
|
||||||
var query = _dbContext.UserTokens
|
var query = _dbContext.UserTokens
|
||||||
.Where(z => z.ValidFrom <= currentDate && z.ValidUntil >= currentDate);
|
.Where(z => z.ValidFrom <= currentDate && z.ValidUntil >= currentDate);
|
||||||
|
|
||||||
// read all tokens, keep the valid ones and remove the expired ones.
|
var tokens = await query.ToArrayAsync();
|
||||||
return query.ToArrayAsync();
|
return tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task RemoveToken(Guid tokenId)
|
public Task RemoveToken(Guid tokenId)
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace Tuitio.Domain.Repositories
|
||||||
public interface IUserRepository
|
public interface IUserRepository
|
||||||
{
|
{
|
||||||
Task<AppUser> GetUser(string userName, string password);
|
Task<AppUser> GetUser(string userName, string password);
|
||||||
Task UpdateUserAfterAuthentication(AppUser user, Token token, string tokenRaw);
|
Task UpdateUserAfterLogin(AppUser user, Token token, string tokenRaw);
|
||||||
Task<UserToken[]> GetActiveTokens();
|
Task<UserToken[]> GetActiveTokens();
|
||||||
Task RemoveToken(Guid tokenId);
|
Task RemoveToken(Guid tokenId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ namespace Tuitio.PublishedLanguage.Constants
|
||||||
{
|
{
|
||||||
public const string
|
public const string
|
||||||
BAD_CREDENTIALS = "BAD_CREDENTIALS",
|
BAD_CREDENTIALS = "BAD_CREDENTIALS",
|
||||||
|
UNAUTHENTICATED = "UNAUTHENTICATED",
|
||||||
UNAUTHORIZED = "UNAUTHORIZED";
|
UNAUTHORIZED = "UNAUTHORIZED";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,25 @@
|
||||||
// Copyright (c) 2020 Tudor Stanciu
|
// Copyright (c) 2020 Tudor Stanciu
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Tuitio.PublishedLanguage.Dto
|
namespace Tuitio.PublishedLanguage.Dto
|
||||||
{
|
{
|
||||||
public record AccountLoginResult(Token Token);
|
public record AccountLoginResult(string Token, double ExpiresIn);
|
||||||
public record AccountLogoutResult(int UserId, string UserName, DateTime LogoutDate);
|
public record AccountLogoutResult(int UserId, string UserName, DateTime LogoutDate);
|
||||||
public record TokenAuthorizationResult(TokenCore TokenCore);
|
public class AuthorizationResult
|
||||||
|
{
|
||||||
|
public Guid TokenId { get; init; }
|
||||||
|
public int UserId { get; init; }
|
||||||
|
public string UserName { get; init; }
|
||||||
|
public string FirstName { get; init; }
|
||||||
|
public string LastName { get; init; }
|
||||||
|
public string Email { get; init; }
|
||||||
|
public string ProfilePictureUrl { get; init; }
|
||||||
|
public string SecurityStamp { get; init; }
|
||||||
|
public string LockStamp { get; init; }
|
||||||
|
public DateTime CreatedAt { get; init; }
|
||||||
|
public double ExpiresIn { get; init; }
|
||||||
|
public Dictionary<string, string> Claims { get; init; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
// Copyright (c) 2020 Tudor Stanciu
|
|
||||||
|
|
||||||
namespace Tuitio.PublishedLanguage.Dto
|
|
||||||
{
|
|
||||||
// move this in result
|
|
||||||
public record Token(string Raw, double ExpiresIn);
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
// Copyright (c) 2020 Tudor Stanciu
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Tuitio.PublishedLanguage.Dto
|
|
||||||
{
|
|
||||||
public class TokenCore
|
|
||||||
{
|
|
||||||
public int UserId { get; set; }
|
|
||||||
public string UserName { get; set; }
|
|
||||||
public string FirstName { get; set; }
|
|
||||||
public string LastName { get; set; }
|
|
||||||
public string Email { get; set; }
|
|
||||||
public string ProfilePictureUrl { get; set; }
|
|
||||||
public string SecurityStamp { get; set; }
|
|
||||||
public string LockStamp { get; set; }
|
|
||||||
public Dictionary<string, string> Claims { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +1,7 @@
|
||||||
2.0.0 release [2023-01-31 02:17]
|
2.1.0 release [2023-03-07 22:17]
|
||||||
|
◾ Tuitio refactoring
|
||||||
|
◾ Added account logout method
|
||||||
|
|
||||||
|
2.0.0 release [2023-01-31 02:17]
|
||||||
◾ Tuitio rebranding
|
◾ Tuitio rebranding
|
||||||
◾ Initial release of Tuitio's published language package
|
◾ Initial release of Tuitio's published language package
|
|
@ -7,7 +7,7 @@
|
||||||
<RepositoryUrl>https://lab.code-rove.com/gitea/tudor.stanciu/tuitio</RepositoryUrl>
|
<RepositoryUrl>https://lab.code-rove.com/gitea/tudor.stanciu/tuitio</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<PackageReleaseNotes>$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/ReleaseNotes.txt"))</PackageReleaseNotes>
|
<PackageReleaseNotes>$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/ReleaseNotes.txt"))</PackageReleaseNotes>
|
||||||
<Version>2.0.0</Version>
|
<Version>2.1.0</Version>
|
||||||
<PackageIcon>logo.png</PackageIcon>
|
<PackageIcon>logo.png</PackageIcon>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<Company>Toodle HomeLab</Company>
|
<Company>Toodle HomeLab</Company>
|
||||||
|
|
|
@ -5,7 +5,8 @@ namespace Tuitio.Wrapper.Constants
|
||||||
internal struct ApiRoutes
|
internal struct ApiRoutes
|
||||||
{
|
{
|
||||||
public const string
|
public const string
|
||||||
Authentication = "account/login?UserName={0}&Password={1}",
|
AccountLogin = "account/login?UserName={0}&Password={1}",
|
||||||
|
AccountLogout = "account/logout?Token={0}",
|
||||||
Authorization = "connect/authorize?Token={0}";
|
Authorization = "connect/authorize?Token={0}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
2.0.0 release [2023-01-31 02:17]
|
2.1.0 release [2023-03-07 22:17]
|
||||||
|
◾ Tuitio refactoring
|
||||||
|
◾ Added account logout method
|
||||||
|
|
||||||
|
2.0.0 release [2023-01-31 02:17]
|
||||||
◾ Tuitio rebranding
|
◾ Tuitio rebranding
|
||||||
◾ Initial release of Tuitio's API wrapper
|
◾ Initial release of Tuitio's API wrapper
|
|
@ -1,13 +1,13 @@
|
||||||
// Copyright (c) 2020 Tudor Stanciu
|
// Copyright (c) 2020 Tudor Stanciu
|
||||||
|
|
||||||
using Tuitio.PublishedLanguage.Dto;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Tuitio.PublishedLanguage.Dto;
|
||||||
|
|
||||||
namespace Tuitio.Wrapper.Services
|
namespace Tuitio.Wrapper.Services
|
||||||
{
|
{
|
||||||
public interface ITuitioService
|
public interface ITuitioService
|
||||||
{
|
{
|
||||||
Task<Token> Authenticate(string userName, string password);
|
Task<AccountLoginResult> Login(string userName, string password);
|
||||||
Task<TokenAuthorizationResult> Authorize(string token);
|
Task<AuthorizationResult> Authorize(string token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
// Copyright (c) 2020 Tudor Stanciu
|
// Copyright (c) 2020 Tudor Stanciu
|
||||||
|
|
||||||
using Tuitio.PublishedLanguage.Dto;
|
|
||||||
using Tuitio.Wrapper.Constants;
|
|
||||||
using Tuitio.Wrapper.Models;
|
|
||||||
using Netmash.Extensions.Http;
|
using Netmash.Extensions.Http;
|
||||||
using System;
|
using System;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Tuitio.PublishedLanguage.Dto;
|
||||||
|
using Tuitio.Wrapper.Constants;
|
||||||
|
using Tuitio.Wrapper.Models;
|
||||||
|
|
||||||
namespace Tuitio.Wrapper.Services
|
namespace Tuitio.Wrapper.Services
|
||||||
{
|
{
|
||||||
|
@ -24,17 +24,24 @@ namespace Tuitio.Wrapper.Services
|
||||||
_httpClient = httpClient;
|
_httpClient = httpClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Token> Authenticate(string userName, string password)
|
public async Task<AccountLoginResult> Login(string userName, string password)
|
||||||
{
|
{
|
||||||
var route = string.Format(ApiRoutes.Authentication, userName, password);
|
var route = string.Format(ApiRoutes.AccountLogin, userName, password);
|
||||||
var result = await _httpClient.ExecutePostRequest<Token>(route);
|
var result = await _httpClient.ExecutePostRequest<AccountLoginResult>(route);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<TokenAuthorizationResult> Authorize(string token)
|
public async Task<AccountLogoutResult> Logout(string token)
|
||||||
|
{
|
||||||
|
var route = string.Format(ApiRoutes.AccountLogout, token);
|
||||||
|
var result = await _httpClient.ExecutePostRequest<AccountLogoutResult>(route);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AuthorizationResult> Authorize(string token)
|
||||||
{
|
{
|
||||||
var route = string.Format(ApiRoutes.Authorization, token);
|
var route = string.Format(ApiRoutes.Authorization, token);
|
||||||
var result = await _httpClient.ExecutePostRequest<TokenAuthorizationResult>(route);
|
var result = await _httpClient.ExecutePostRequest<AuthorizationResult>(route);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<RepositoryUrl>https://lab.code-rove.com/gitea/tudor.stanciu/tuitio</RepositoryUrl>
|
<RepositoryUrl>https://lab.code-rove.com/gitea/tudor.stanciu/tuitio</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<PackageReleaseNotes>$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/ReleaseNotes.txt"))</PackageReleaseNotes>
|
<PackageReleaseNotes>$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/ReleaseNotes.txt"))</PackageReleaseNotes>
|
||||||
<Version>2.0.0</Version>
|
<Version>2.1.0</Version>
|
||||||
<PackageIcon>logo.png</PackageIcon>
|
<PackageIcon>logo.png</PackageIcon>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<Company>Toodle HomeLab</Company>
|
<Company>Toodle HomeLab</Company>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
using MediatR;
|
// Copyright (c) 2020 Tudor Stanciu
|
||||||
|
|
||||||
|
using MediatR;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Tuitio.Application.CommandHandlers;
|
using Tuitio.Application.CommandHandlers;
|
||||||
|
@ -27,12 +29,9 @@ namespace Tuitio.Controllers
|
||||||
[HttpPost("logout")]
|
[HttpPost("logout")]
|
||||||
public async Task<IActionResult> Logout([FromQuery] string token)
|
public async Task<IActionResult> Logout([FromQuery] string token)
|
||||||
{
|
{
|
||||||
var result = await _mediator.Send(token);
|
var command = new AccountLogoutHandler.Command(token);
|
||||||
|
var result = await _mediator.Send(command);
|
||||||
if (result != null)
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
else
|
|
||||||
return BadRequest();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace Tuitio.Api.Controllers
|
||||||
[HttpPost("authorize")]
|
[HttpPost("authorize")]
|
||||||
public async Task<IActionResult> AuthorizeToken([FromQuery] string token)
|
public async Task<IActionResult> AuthorizeToken([FromQuery] string token)
|
||||||
{
|
{
|
||||||
var command = new AuthorizeTokenHandler.Command(token);
|
var command = new AuthorizationHandler.Command(token);
|
||||||
var result = await _mediator.Send(command);
|
var result = await _mediator.Send(command);
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,8 @@ namespace Tuitio.Api.Controllers
|
||||||
[Route("system")]
|
[Route("system")]
|
||||||
public class SystemController : ControllerBase
|
public class SystemController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly IMediator _mediator;
|
|
||||||
|
|
||||||
public SystemController(IMediator mediator)
|
public SystemController(IMediator mediator)
|
||||||
{
|
{
|
||||||
_mediator = mediator;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
|
@ -24,12 +21,5 @@ namespace Tuitio.Api.Controllers
|
||||||
{
|
{
|
||||||
return Ok($"Ping success. System datetime: {DateTime.Now}");
|
return Ok($"Ping success. System datetime: {DateTime.Now}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Methods:
|
|
||||||
/version
|
|
||||||
/burn-token
|
|
||||||
/burn-all-tokens
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue