identity server methods
parent
aa71156974
commit
5416c982a5
|
@ -0,0 +1,41 @@
|
|||
using IdentityServer.Application.Commands;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IdentityServer.Api.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("identity")]
|
||||
public class IdentityController : ControllerBase
|
||||
{
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
public IdentityController(IMediator mediator)
|
||||
{
|
||||
_mediator = mediator;
|
||||
}
|
||||
|
||||
[HttpPost("authenticate/{userName}/{password}")]
|
||||
public async Task<IActionResult> AuthenticateUser([FromRoute] AuthenticateUser authenticateUser)
|
||||
{
|
||||
var result = await _mediator.Send(authenticateUser);
|
||||
|
||||
if (result != null)
|
||||
return Ok(result);
|
||||
else
|
||||
return BadRequest();
|
||||
}
|
||||
|
||||
[HttpPost("authorize/{token}")]
|
||||
public async Task<IActionResult> AuthorizeToken([FromRoute] AuthorizeToken authorizeToken)
|
||||
{
|
||||
var result = await _mediator.Send(authorizeToken);
|
||||
|
||||
if (result != null)
|
||||
return Ok(result);
|
||||
else
|
||||
return BadRequest();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IdentityServer.Api.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
public class WeatherForecastController : ControllerBase
|
||||
{
|
||||
private static readonly string[] Summaries = new[]
|
||||
{
|
||||
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
|
||||
};
|
||||
|
||||
private readonly ILogger<WeatherForecastController> _logger;
|
||||
|
||||
public WeatherForecastController(ILogger<WeatherForecastController> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IEnumerable<WeatherForecast> Get()
|
||||
{
|
||||
var rng = new Random();
|
||||
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
|
||||
{
|
||||
Date = DateTime.Now.AddDays(index),
|
||||
TemperatureC = rng.Next(-20, 55),
|
||||
Summary = Summaries[rng.Next(Summaries.Length)]
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,27 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.4" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="$(MicrosoftExtensionsPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="$(MicrosoftExtensionsPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="$(MicrosoftExtensionsPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="$(MicrosoftExtensionsPackageVersion)" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="$(SerilogPackageVersion)" />
|
||||
<PackageReference Include="Serilog.Extensions.Logging" Version="$(SerilogExtensionsPackageVersion)" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="$(SerilogSinksConsolePackageVersion)" />
|
||||
<PackageReference Include="Serilog.Sinks.MSSqlServer" Version="$(SerilogSinksMSSqlServerPackageVersion)" />
|
||||
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="$(AutoMapperExtensionsPackageVersion)" />
|
||||
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="$(MediatRPackageVersion)" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="$(SwashbucklePackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="$(MicrosoftExtensionsPackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\IdentityServer.Application\IdentityServer.Application.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace IdentityServer.Api
|
||||
{
|
||||
public class WeatherForecast
|
||||
{
|
||||
public DateTime Date { get; set; }
|
||||
|
||||
public int TemperatureC { get; set; }
|
||||
|
||||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
||||
|
||||
public string Summary { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace IdentityServer.Application
|
||||
{
|
||||
public class Class1
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
using AutoMapper;
|
||||
using IdentityServer.Application.Commands;
|
||||
using IdentityServer.Application.Services;
|
||||
using IdentityServer.PublishedLanguage.Dto;
|
||||
using MediatR;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IdentityServer.Application.CommandHandlers
|
||||
{
|
||||
public class AuthenticateUserHandler : IRequestHandler<AuthenticateUser, Token>
|
||||
{
|
||||
private readonly IUserService _userService;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public AuthenticateUserHandler(IUserService userService, IMapper mapper)
|
||||
{
|
||||
_userService = userService;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<Token> Handle(AuthenticateUser command, CancellationToken cancellationToken)
|
||||
{
|
||||
var internalToken = await _userService.Authenticate(command.UserName, command.Password);
|
||||
if (internalToken == null)
|
||||
return null;
|
||||
|
||||
var token = _mapper.Map<Token>(internalToken);
|
||||
return token;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
using AutoMapper;
|
||||
using IdentityServer.Application.Commands;
|
||||
using IdentityServer.Application.Services;
|
||||
using IdentityServer.PublishedLanguage.Dto;
|
||||
using MediatR;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IdentityServer.Application.CommandHandlers
|
||||
{
|
||||
public class AuthorizeTokenHandler : IRequestHandler<AuthorizeToken, User>
|
||||
{
|
||||
private readonly IUserService _userService;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public AuthorizeTokenHandler(IUserService userService, IMapper mapper)
|
||||
{
|
||||
_userService = userService;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<User> Handle(AuthorizeToken command, CancellationToken cancellationToken)
|
||||
{
|
||||
var appUser = await _userService.Authorize(command.Token);
|
||||
if (appUser == null)
|
||||
return null;
|
||||
|
||||
var user = _mapper.Map<User>(appUser);
|
||||
return user;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
using IdentityServer.PublishedLanguage.Dto;
|
||||
|
||||
namespace IdentityServer.Application.Commands
|
||||
{
|
||||
public class AuthenticateUser : Command<Token>
|
||||
{
|
||||
public string UserName { get; set; }
|
||||
public string Password { get; set; }
|
||||
|
||||
public AuthenticateUser(string userName, string password)
|
||||
{
|
||||
UserName = userName;
|
||||
Password = password;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using IdentityServer.PublishedLanguage.Dto;
|
||||
|
||||
namespace IdentityServer.Application.Commands
|
||||
{
|
||||
public class AuthorizeToken : Command<User>
|
||||
{
|
||||
public string Token { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
using MediatR;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace IdentityServer.Application.Commands
|
||||
{
|
||||
public abstract class Command<TResponse> : ICommand, IRequest<TResponse>
|
||||
{
|
||||
public Metadata Metadata { get; }
|
||||
|
||||
protected Command()
|
||||
{
|
||||
Metadata = new Metadata() { CorrelationId = Guid.NewGuid() };
|
||||
}
|
||||
|
||||
protected Command(Metadata metadata)
|
||||
{
|
||||
Metadata = metadata;
|
||||
}
|
||||
}
|
||||
|
||||
public interface ICommand
|
||||
{
|
||||
}
|
||||
|
||||
public class Metadata : Dictionary<string, string>
|
||||
{
|
||||
public const string CorrelationIdKey = "CorrelationId";
|
||||
|
||||
public Guid CorrelationId
|
||||
{
|
||||
get
|
||||
{
|
||||
return Guid.Parse(this[CorrelationIdKey]);
|
||||
}
|
||||
set
|
||||
{
|
||||
if (ContainsKey(CorrelationIdKey))
|
||||
this[CorrelationIdKey] = value.ToString();
|
||||
else
|
||||
Add(CorrelationIdKey, value.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
using IdentityServer.Application.Services;
|
||||
using IdentityServer.Application.Stores;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace IdentityServer.Application
|
||||
{
|
||||
public static class DependencyInjectionExtensions
|
||||
{
|
||||
public static void AddApplicationServices(this IServiceCollection services)
|
||||
{
|
||||
services.AddStores();
|
||||
services.AddScoped<IUserService, UserService>();
|
||||
}
|
||||
|
||||
private static void AddStores(this IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<ISecurityStore, SecurityStore>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,4 +4,18 @@
|
|||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="$(AutoMapperPackageVersion)" />
|
||||
<PackageReference Include="MediatR" Version="$(MediatRPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="$(MicrosoftExtensionsPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="$(MicrosoftExtensionsPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="$(MicrosoftExtensionsPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="$(MicrosoftExtensionsPackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\IdentityServer.Domain\IdentityServer.Domain.csproj" />
|
||||
<ProjectReference Include="..\IdentityServer.PublishedLanguage\IdentityServer.PublishedLanguage.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
using AutoMapper;
|
||||
using IdentityServer.Domain.Entities;
|
||||
using dto = IdentityServer.PublishedLanguage.Dto;
|
||||
using models = IdentityServer.Domain.Models;
|
||||
|
||||
namespace IdentityServer.Application.Mappings
|
||||
{
|
||||
public class MappingProfile : Profile
|
||||
{
|
||||
public MappingProfile()
|
||||
{
|
||||
CreateMap<models.Token, dto.Token>();
|
||||
CreateMap<AppUser, dto.User>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
using MediatR;
|
||||
|
||||
namespace IdentityServer.Application.Queries
|
||||
{
|
||||
public abstract class Query<TResponse> : IRequest<TResponse>, IBaseRequest { }
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using IdentityServer.Domain.Entities;
|
||||
using IdentityServer.Domain.Models;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IdentityServer.Application.Services
|
||||
{
|
||||
public interface IUserService
|
||||
{
|
||||
Task<Token> Authenticate(string userName, string password);
|
||||
Task<AppUser> Authorize(string token);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
using IdentityServer.Application.Stores;
|
||||
using IdentityServer.Domain.Entities;
|
||||
using IdentityServer.Domain.Models;
|
||||
using IdentityServer.Domain.Repositories;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IdentityServer.Application.Services
|
||||
{
|
||||
public class UserService : IUserService
|
||||
{
|
||||
private readonly ISecurityStore _securityStore;
|
||||
private readonly IIdentityRepository _identityRepository;
|
||||
|
||||
public UserService(ISecurityStore securityStore, IIdentityRepository identityRepository)
|
||||
{
|
||||
_securityStore = securityStore;
|
||||
_identityRepository = identityRepository;
|
||||
}
|
||||
|
||||
public async Task<Token> Authenticate(string userName, string password)
|
||||
{
|
||||
var user = await _identityRepository.GetAppUser(userName, password);
|
||||
if (user == null)
|
||||
return null;
|
||||
|
||||
var tokenRaw = $"{Guid.NewGuid()}-{Guid.NewGuid()}-{user.UserId}";
|
||||
_securityStore.SetToken(tokenRaw, user.UserId);
|
||||
|
||||
var token = new Token() { Raw = tokenRaw };
|
||||
return token;
|
||||
}
|
||||
|
||||
public async Task<AppUser> Authorize(string token)
|
||||
{
|
||||
var tokenValidation = _securityStore.ValidateToken(token);
|
||||
if (tokenValidation.Success)
|
||||
{
|
||||
var user = await _identityRepository.GetAppUser(tokenValidation.UserId);
|
||||
return user;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
using IdentityServer.Domain.Models;
|
||||
|
||||
namespace IdentityServer.Application.Stores
|
||||
{
|
||||
public interface ISecurityStore
|
||||
{
|
||||
void SetToken(string token, int userId);
|
||||
TokenValidation ValidateToken(string token);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
using IdentityServer.Domain.Models;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace IdentityServer.Application.Stores
|
||||
{
|
||||
public class SecurityStore : ISecurityStore
|
||||
{
|
||||
private ConcurrentDictionary<int, List<Token>> Tokens { get; }
|
||||
|
||||
public SecurityStore()
|
||||
{
|
||||
Tokens = new ConcurrentDictionary<int, List<Token>>();
|
||||
}
|
||||
|
||||
public void SetToken(string token, int userId)
|
||||
{
|
||||
var registered = Tokens.TryGetValue(userId, out List<Token> list);
|
||||
|
||||
if (registered)
|
||||
list.Add(new Token() { Raw = token });
|
||||
else
|
||||
Tokens.TryAdd(userId, new List<Token>() { new Token() { Raw = token } });
|
||||
}
|
||||
|
||||
public TokenValidation ValidateToken(string token)
|
||||
{
|
||||
var lastIndexOfSeparator = token.LastIndexOf('-') + 1;
|
||||
var userIdString = token.Substring(lastIndexOfSeparator, token.Length - lastIndexOfSeparator);
|
||||
|
||||
if (!int.TryParse(userIdString, out int userId))
|
||||
return InvalidToken;
|
||||
|
||||
var registered = Tokens.TryGetValue(userId, out List<Token> list);
|
||||
|
||||
if (!registered)
|
||||
return InvalidToken;
|
||||
|
||||
var valid = list.FirstOrDefault(z => z.Raw == token);
|
||||
if (valid != null)
|
||||
return new TokenValidation() { Success = true, UserId = userId };
|
||||
|
||||
return InvalidToken;
|
||||
}
|
||||
|
||||
private TokenValidation InvalidToken => new TokenValidation() { Success = false };
|
||||
}
|
||||
}
|
|
@ -15,6 +15,11 @@ namespace IdentityServer.Domain.Data.Repositories
|
|||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
public Task<AppUser> GetAppUser(int userId)
|
||||
{
|
||||
return _dbContext.AppUsers.FirstOrDefaultAsync(z => z.UserId == userId);
|
||||
}
|
||||
|
||||
public Task<AppUser> GetAppUser(string userName, string password)
|
||||
{
|
||||
return _dbContext.AppUsers.FirstOrDefaultAsync(z => z.UserName == userName && z.Password == password);
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
|
||||
namespace IdentityServer.Domain.Models
|
||||
{
|
||||
public class Token
|
||||
{
|
||||
public string Raw { get; set; }
|
||||
public DateTime ValidUntil { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace IdentityServer.Domain.Models
|
||||
{
|
||||
public class TokenValidation
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public int UserId { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,10 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using IdentityServer.Domain.Entities;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IdentityServer.Domain.Repositories
|
||||
{
|
||||
public interface IIdentityRepository
|
||||
{
|
||||
Task<AppUser> GetAppUser(int userId);
|
||||
Task<AppUser> GetAppUser(string userName, string password);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
|
||||
namespace IdentityServer.PublishedLanguage.Dto
|
||||
{
|
||||
public class Token
|
||||
{
|
||||
public string Raw { get; set; }
|
||||
public DateTime ValidUntil { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace IdentityServer.PublishedLanguage.Dto
|
||||
{
|
||||
public class User
|
||||
{
|
||||
public int UserId { get; set; }
|
||||
public string UserName { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
|
@ -21,6 +21,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IdentityServer.Domain", "Id
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IdentityServer.Domain.Data", "IdentityServer.Domain.Data\IdentityServer.Domain.Data.csproj", "{CE81A435-49AC-4544-A381-FAC91BEB3C49}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IdentityServer.PublishedLanguage", "IdentityServer.PublishedLanguage\IdentityServer.PublishedLanguage.csproj", "{67B4D1FF-D02E-4DA6-9FB8-F71667360448}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -43,6 +45,10 @@ Global
|
|||
{CE81A435-49AC-4544-A381-FAC91BEB3C49}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CE81A435-49AC-4544-A381-FAC91BEB3C49}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CE81A435-49AC-4544-A381-FAC91BEB3C49}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{67B4D1FF-D02E-4DA6-9FB8-F71667360448}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{67B4D1FF-D02E-4DA6-9FB8-F71667360448}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{67B4D1FF-D02E-4DA6-9FB8-F71667360448}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{67B4D1FF-D02E-4DA6-9FB8-F71667360448}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -52,6 +58,7 @@ Global
|
|||
{6556D255-AF22-478E-A71A-BE37C16D5EE4} = {5A8FF505-3E4D-4258-BC3E-CACD74A7B98C}
|
||||
{5890B079-3CB0-4AD6-8809-BB2E081590B1} = {5A8FF505-3E4D-4258-BC3E-CACD74A7B98C}
|
||||
{CE81A435-49AC-4544-A381-FAC91BEB3C49} = {5A8FF505-3E4D-4258-BC3E-CACD74A7B98C}
|
||||
{67B4D1FF-D02E-4DA6-9FB8-F71667360448} = {5A8FF505-3E4D-4258-BC3E-CACD74A7B98C}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {E93DC46D-9C55-4A05-B299-497CDD90747E}
|
||||
|
|
|
@ -5,3 +5,7 @@ dotnet publish --configuration Release --runtime win7-x64
|
|||
Create windows service:
|
||||
sc create NetworkResurrector.Api binPath= "<path_to_the_service_executable>"
|
||||
#######################################################################################################################################################
|
||||
|
||||
|
||||
TO DO:
|
||||
- Cache for users
|
Loading…
Reference in New Issue