#384 Авторизации + получение id пользователя в контроллерах #3
@ -1,10 +1,12 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Persistence.Models;
|
using Persistence.Models;
|
||||||
using Persistence.Repositories;
|
using Persistence.Repositories;
|
||||||
|
|
||||||
namespace Persistence.API.Controllers
|
namespace Persistence.API.Controllers
|
||||||
{
|
{
|
||||||
[ApiController]
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
public class SetpointController : ControllerBase, ISetpointApi
|
public class SetpointController : ControllerBase, ISetpointApi
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using Microsoft.OpenApi.Any;
|
using Microsoft.OpenApi.Any;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
|
using Persistence.Models;
|
||||||
|
using Persistence.Models.Configurations;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Text;
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
|
|
||||||
namespace Persistence.API;
|
namespace Persistence.API;
|
||||||
@ -30,59 +36,144 @@ public static class DependencyInjection
|
|||||||
});
|
});
|
||||||
|
|
||||||
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Persistence web api", Version = "v1" });
|
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Persistence web api", Version = "v1" });
|
||||||
c.AddSecurityDefinition("Keycloack", new OpenApiSecurityScheme
|
|
||||||
{
|
|
||||||
Description = @"JWT Authorization header using the Bearer scheme. Enter 'Bearer' [space] and then your token in the text input below. Example: 'Bearer 12345abcdef'",
|
|
||||||
Name = "Authorization",
|
|
||||||
In = ParameterLocation.Header,
|
|
||||||
Type = SecuritySchemeType.OAuth2,
|
|
||||||
Flows = new OpenApiOAuthFlows
|
|
||||||
{
|
|
||||||
Implicit = new OpenApiOAuthFlow
|
|
||||||
{
|
|
||||||
AuthorizationUrl = new Uri(configuration["Authentication:AuthorizationUrl"]),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
c.AddSecurityRequirement(new OpenApiSecurityRequirement()
|
var needUseKeyCloak = configuration.GetSection("NeedUseKeyCloak").Get<bool>();
|
||||||
{
|
if (needUseKeyCloak)
|
||||||
|
|||||||
{
|
{
|
||||||
new OpenApiSecurityScheme
|
c.AddSecurityDefinition("Keycloack", new OpenApiSecurityScheme
|
||||||
{
|
{
|
||||||
Reference = new OpenApiReference
|
Description = @"JWT Authorization header using the Bearer scheme. Enter 'Bearer' [space] and then your token in the text input below. Example: 'Bearer 12345abcdef'",
|
||||||
{
|
Name = "Authorization",
|
||||||
Type = ReferenceType.SecurityScheme,
|
In = ParameterLocation.Header,
|
||||||
Id = "Keycloack"
|
Type = SecuritySchemeType.OAuth2,
|
||||||
},
|
Flows = new OpenApiOAuthFlows
|
||||||
Scheme = "Bearer",
|
{
|
||||||
Name = "Bearer",
|
Implicit = new OpenApiOAuthFlow
|
||||||
In = ParameterLocation.Header,
|
{
|
||||||
},
|
AuthorizationUrl = new Uri(configuration["Authentication:AuthorizationUrl"]),
|
||||||
new List<string>()
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
c.AddSecurityRequirement(new OpenApiSecurityRequirement()
|
||||||
//var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
|
{
|
||||||
//var includeControllerXmlComment = true;
|
{
|
||||||
//c.IncludeXmlComments(xmlPath, includeControllerXmlComment);
|
new OpenApiSecurityScheme
|
||||||
//c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "AsbCloudApp.xml"), includeControllerXmlComment);
|
{
|
||||||
});
|
Reference = new OpenApiReference
|
||||||
|
{
|
||||||
|
Type = ReferenceType.SecurityScheme,
|
||||||
|
Id = "Keycloack"
|
||||||
|
},
|
||||||
|
Scheme = "Bearer",
|
||||||
|
Name = "Bearer",
|
||||||
|
In = ParameterLocation.Header,
|
||||||
|
},
|
||||||
|
new List<string>()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
|
||||||
|
{
|
||||||
|
Description = @"JWT Authorization header using the Bearer scheme. Enter 'Bearer' [space] and then your token in the text input below. Example: 'Bearer 12345abcdef'",
|
||||||
|
Name = "Authorization",
|
||||||
|
In = ParameterLocation.Header,
|
||||||
|
Type = SecuritySchemeType.ApiKey,
|
||||||
|
Scheme = "Bearer",
|
||||||
|
});
|
||||||
|
|
||||||
|
c.AddSecurityRequirement(new OpenApiSecurityRequirement()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
new OpenApiSecurityScheme
|
||||||
|
{
|
||||||
|
Reference = new OpenApiReference
|
||||||
|
{
|
||||||
|
Type = ReferenceType.SecurityScheme,
|
||||||
|
Id = "Bearer"
|
||||||
|
},
|
||||||
|
Scheme = "oauth2",
|
||||||
|
Name = "Bearer",
|
||||||
|
In = ParameterLocation.Header,
|
||||||
|
},
|
||||||
|
new List<string>()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
||||||
|
//var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
|
||||||
|
//var includeControllerXmlComment = true;
|
||||||
|
//c.IncludeXmlComments(xmlPath, includeControllerXmlComment);
|
||||||
|
//c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "AsbCloudApp.xml"), includeControllerXmlComment);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddJWTAuthentication(this IServiceCollection services, IConfiguration configuration)
|
public static void AddJWTAuthentication(this IServiceCollection services, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
var needUseKeyCloak = configuration
|
||||||
.AddJwtBearer(o =>
|
.GetSection("NeedUseKeyCloak")
|
||||||
{
|
.Get<bool>();
|
||||||
o.RequireHttpsMetadata = false;
|
if (needUseKeyCloak) services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||||
on.nemtina
commented
Тут тоже как будто хочется 2 отдельных метода использовать: AddAuthenticationKeyCloak и AddAuthenticationJWT Тут тоже как будто хочется 2 отдельных метода использовать: AddAuthenticationKeyCloak и AddAuthenticationJWT
rs.efremov
commented
AddKeycloackSecurity и AddDefaultSecurity. Просто и то и другое по факту bearer jwt AddKeycloackSecurity и AddDefaultSecurity. Просто и то и другое по факту bearer jwt
|
|||||||
o.Audience = configuration["Authentication:Audience"];
|
.AddJwtBearer(options =>
|
||||||
o.MetadataAddress = configuration["Authentication:MetadataAddress"]!;
|
{
|
||||||
o.TokenValidationParameters = new TokenValidationParameters
|
options.RequireHttpsMetadata = false;
|
||||||
{
|
options.Audience = configuration["Authentication:Audience"];
|
||||||
ValidIssuer = configuration["Authentication:ValidIssuer"],
|
options.MetadataAddress = configuration["Authentication:MetadataAddress"]!;
|
||||||
};
|
options.TokenValidationParameters = new TokenValidationParameters
|
||||||
});
|
{
|
||||||
}
|
ValidIssuer = configuration["Authentication:ValidIssuer"],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
else services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||||
|
.AddJwtBearer(options =>
|
||||||
|
{
|
||||||
|
options.RequireHttpsMetadata = false;
|
||||||
|
options.TokenValidationParameters = new TokenValidationParameters
|
||||||
|
{
|
||||||
|
ValidateIssuer = true,
|
||||||
|
ValidIssuer = JwtParams.Issuer,
|
||||||
|
ValidateAudience = true,
|
||||||
|
ValidAudience = JwtParams.Audience,
|
||||||
|
ValidateLifetime = true,
|
||||||
|
IssuerSigningKey = JwtParams.SecurityKey,
|
||||||
|
ValidateIssuerSigningKey = false
|
||||||
|
};
|
||||||
|
options.Events = new JwtBearerEvents
|
||||||
|
{
|
||||||
|
OnMessageReceived = context =>
|
||||||
|
{
|
||||||
|
var accessToken = context.Request.Headers["Authorization"]
|
||||||
|
.ToString()
|
||||||
|
.Replace(JwtBearerDefaults.AuthenticationScheme, string.Empty)
|
||||||
|
.Trim();
|
||||||
|
|
||||||
|
context.Token = accessToken;
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
},
|
||||||
|
OnTokenValidated = context =>
|
||||||
|
{
|
||||||
|
var username = context.Principal?.Claims
|
||||||
|
.FirstOrDefault(e => e.Type == "username")?.Value;
|
||||||
|
|
||||||
|
var password = context.Principal?.Claims
|
||||||
|
.FirstOrDefault(e => e.Type == "password")?.Value;
|
||||||
|
|
||||||
|
var keyCloakUser = configuration
|
||||||
|
.GetSection(nameof(AuthUser))
|
||||||
|
.Get<AuthUser>()!;
|
||||||
|
|
||||||
|
if (username != keyCloakUser.Username || password != keyCloakUser.Password)
|
||||||
|
{
|
||||||
|
context.Fail("username or password did not match");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
},
|
},
|
||||||
"dotnetRunMessages": true,
|
"dotnetRunMessages": true,
|
||||||
"applicationUrl": "http://localhost:5032"
|
"applicationUrl": "http://localhost:13616"
|
||||||
},
|
},
|
||||||
"IIS Express": {
|
"IIS Express": {
|
||||||
"commandName": "IISExpress",
|
"commandName": "IISExpress",
|
||||||
|
@ -4,5 +4,6 @@
|
|||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
"Microsoft.AspNetCore": "Warning"
|
"Microsoft.AspNetCore": "Warning"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"NeedUseKeyCloak": false
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
{
|
{
|
||||||
"DbConnection": {
|
"DbConnection": {
|
||||||
"Host": "localhost",
|
"Host": "localhost",
|
||||||
"Port": 5432,
|
"Port": 5432,
|
||||||
"Username": "postgres",
|
"Username": "postgres",
|
||||||
"Password": "q"
|
"Password": "q"
|
||||||
},
|
},
|
||||||
"KeycloakTestUser": {
|
"NeedUseKeyCloak": false,
|
||||||
|
"AuthUser": {
|
||||||
"username": "myuser",
|
"username": "myuser",
|
||||||
"password": 12345,
|
"password": 12345,
|
||||||
"clientId": "webapi",
|
"clientId": "webapi",
|
||||||
|
@ -1,43 +1,72 @@
|
|||||||
namespace Persistence.Client.Helpers;
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Text.Json;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using Persistence.Models.Configurations;
|
||||||
|
using RestSharp;
|
||||||
|
|
||||||
|
namespace Persistence.Client.Helpers;
|
||||||
public static class ApiTokenHelper
|
public static class ApiTokenHelper
|
||||||
{
|
{
|
||||||
public static string GetAdminUserToken()
|
public static void Authorize(this HttpClient httpClient, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
//var user = new User()
|
var authUser = configuration
|
||||||
//{
|
.GetSection(nameof(AuthUser))
|
||||||
// Id = 1,
|
.Get<AuthUser>()!;
|
||||||
// IdCompany = 1,
|
var needUseKeyCloak = configuration
|
||||||
// Login = "test_user"
|
.GetSection("NeedUseKeyCloak")
|
||||||
//};
|
.Get<bool>()!;
|
||||||
//var roles = new[] { "root" };
|
var keycloakGetTokenUrl = configuration.GetSection("KeycloakGetTokenUrl").Get<string>() ?? string.Empty;
|
||||||
|
|
||||||
return string.Empty;
|
var jwtToken = needUseKeyCloak
|
||||||
}
|
? authUser.CreateKeyCloakJwtToken(keycloakGetTokenUrl)
|
||||||
|
: authUser.CreateDefaultJwtToken();
|
||||||
|
|
||||||
//private static string CreateToken(User user, IEnumerable<string> roles)
|
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken);
|
||||||
//{
|
}
|
||||||
// var claims = new List<Claim>
|
|
||||||
// {
|
|
||||||
// new("id", user.Id.ToString()),
|
|
||||||
// new(ClaimsIdentity.DefaultNameClaimType, user.Login),
|
|
||||||
// new("idCompany", user.IdCompany.ToString()),
|
|
||||||
// };
|
|
||||||
|
|
||||||
// claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));
|
private static string CreateDefaultJwtToken(this AuthUser authUser)
|
||||||
|
{
|
||||||
|
var claims = new List<Claim>()
|
||||||
|
{
|
||||||
|
new("client_id", authUser.ClientId),
|
||||||
|
new("username", authUser.Username),
|
||||||
|
new("password", authUser.Password),
|
||||||
|
new("grant_type", authUser.GrantType)
|
||||||
|
};
|
||||||
|
|
||||||
// const string secret = "супер секретный ключ для шифрования";
|
var tokenDescriptor = new SecurityTokenDescriptor
|
||||||
|
{
|
||||||
|
Issuer = JwtParams.Issuer,
|
||||||
|
Audience = JwtParams.Audience,
|
||||||
|
Subject = new ClaimsIdentity(claims),
|
||||||
|
Expires = DateTime.UtcNow.AddHours(1),
|
||||||
|
SigningCredentials = new SigningCredentials(JwtParams.SecurityKey, SecurityAlgorithms.HmacSha256Signature)
|
||||||
|
};
|
||||||
|
var tokenHandler = new JwtSecurityTokenHandler();
|
||||||
|
var token = tokenHandler.CreateToken(tokenDescriptor);
|
||||||
|
return tokenHandler.WriteToken(token);
|
||||||
|
}
|
||||||
|
|
||||||
// var key = Encoding.ASCII.GetBytes(secret);
|
private static string CreateKeyCloakJwtToken(this AuthUser authUser, string keycloakGetTokenUrl)
|
||||||
// var tokenDescriptor = new SecurityTokenDescriptor
|
{
|
||||||
// {
|
var restClient = new RestClient();
|
||||||
// Issuer = "a",
|
|
||||||
// Audience = "a",
|
var request = new RestRequest(keycloakGetTokenUrl, Method.Post);
|
||||||
// Subject = new ClaimsIdentity(claims),
|
request.AddParameter("username", authUser.Username);
|
||||||
// Expires = DateTime.UtcNow.AddHours(1),
|
request.AddParameter("password", authUser.Password);
|
||||||
// SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
|
request.AddParameter("client_id", authUser.ClientId);
|
||||||
// };
|
request.AddParameter("grant_type", authUser.GrantType);
|
||||||
// var tokenHandler = new JwtSecurityTokenHandler();
|
|
||||||
// var token = tokenHandler.CreateToken(tokenDescriptor);
|
var keyCloackResponse = restClient.Post(request);
|
||||||
// return tokenHandler.WriteToken(token);
|
if (keyCloackResponse.IsSuccessful && !String.IsNullOrEmpty(keyCloackResponse.Content))
|
||||||
//}
|
{
|
||||||
|
var token = JsonSerializer.Deserialize<JwtToken>(keyCloackResponse.Content)!;
|
||||||
|
return token.AccessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
return String.Empty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,12 +7,19 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.2.1" />
|
||||||
<PackageReference Include="Refit" Version="8.0.0" />
|
<PackageReference Include="Refit" Version="8.0.0" />
|
||||||
<PackageReference Include="Refit.HttpClientFactory" Version="8.0.0" />
|
<PackageReference Include="Refit.HttpClientFactory" Version="8.0.0" />
|
||||||
|
<PackageReference Include="RestSharp" Version="112.1.0" />
|
||||||
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.2.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Persistence\Persistence.csproj" />
|
<ProjectReference Include="..\Persistence\Persistence.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Models\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -1,48 +1,30 @@
|
|||||||
using System;
|
using System.Text.Json;
|
||||||
using System.Collections.Generic;
|
using Microsoft.Extensions.Configuration;
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Http.Headers;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using Refit;
|
|
||||||
using Persistence.Client.Helpers;
|
using Persistence.Client.Helpers;
|
||||||
|
using Persistence.Models.Configurations;
|
||||||
|
using Refit;
|
||||||
|
|
||||||
namespace Persistence.Client
|
namespace Persistence.Client
|
||||||
{
|
{
|
||||||
public static class PersistenceClientFactory
|
public class PersistenceClientFactory
|
||||||
{
|
{
|
||||||
|
|
||||||
private static readonly JsonSerializerOptions JsonSerializerOptions = new()
|
private static readonly JsonSerializerOptions JsonSerializerOptions = new()
|
||||||
{
|
{
|
||||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||||
PropertyNameCaseInsensitive = true
|
PropertyNameCaseInsensitive = true
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly RefitSettings RefitSettings = new(new SystemTextJsonContentSerializer(JsonSerializerOptions));
|
private static readonly RefitSettings RefitSettings = new(new SystemTextJsonContentSerializer(JsonSerializerOptions));
|
||||||
|
private HttpClient httpClient;
|
||||||
public static T GetClient<T>(HttpClient client)
|
public PersistenceClientFactory(IHttpClientFactory httpClientFactory, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
return RestService.For<T>(client, RefitSettings);
|
this.httpClient = httpClientFactory.CreateClient();
|
||||||
|
|
||||||
|
httpClient.Authorize(configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static T GetClient<T>(string baseUrl)
|
public T GetClient<T>()
|
||||||
{
|
{
|
||||||
var client = new HttpClient();
|
return RestService.For<T>(httpClient, RefitSettings);
|
||||||
client.BaseAddress = new Uri(baseUrl);
|
|
||||||
|
|
||||||
return RestService.For<T>(client, RefitSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static HttpClient GetAuthorizedClient()
|
|
||||||
{
|
|
||||||
var httpClient = new HttpClient();
|
|
||||||
var jwtToken = ApiTokenHelper.GetAdminUserToken();
|
|
||||||
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken);
|
|
||||||
|
|
||||||
return httpClient;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
namespace Persistence.IntegrationTests;
|
|
||||||
public static class ApiTokenHelper
|
|
||||||
{
|
|
||||||
//public static string GetAdminUserToken()
|
|
||||||
//{
|
|
||||||
// var user = new User()
|
|
||||||
// {
|
|
||||||
// Id = 1,
|
|
||||||
// IdCompany = 1,
|
|
||||||
// Login = "test_user"
|
|
||||||
// };
|
|
||||||
// var roles = new[] { "root" };
|
|
||||||
|
|
||||||
// return CreateToken(user, roles);
|
|
||||||
//}
|
|
||||||
|
|
||||||
//private static string CreateToken(User user, IEnumerable<string> roles)
|
|
||||||
//{
|
|
||||||
// var claims = new List<Claim>
|
|
||||||
// {
|
|
||||||
// new("id", user.Id.ToString()),
|
|
||||||
// new(ClaimsIdentity.DefaultNameClaimType, user.Login),
|
|
||||||
// new("idCompany", user.IdCompany.ToString()),
|
|
||||||
// };
|
|
||||||
|
|
||||||
// claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));
|
|
||||||
|
|
||||||
// const string secret = "супер секретный ключ для шифрования";
|
|
||||||
|
|
||||||
// var key = Encoding.ASCII.GetBytes(secret);
|
|
||||||
// var tokenDescriptor = new SecurityTokenDescriptor
|
|
||||||
// {
|
|
||||||
// Issuer = "a",
|
|
||||||
// Audience = "a",
|
|
||||||
// Subject = new ClaimsIdentity(claims),
|
|
||||||
// Expires = DateTime.UtcNow.AddHours(1),
|
|
||||||
// SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
|
|
||||||
// };
|
|
||||||
// var tokenHandler = new JwtSecurityTokenHandler();
|
|
||||||
// var token = tokenHandler.CreateToken(tokenDescriptor);
|
|
||||||
// return tokenHandler.WriteToken(token);
|
|
||||||
//}
|
|
||||||
}
|
|
@ -17,11 +17,10 @@ namespace Persistence.IntegrationTests.Controllers
|
|||||||
public SetpointControllerTest(WebAppFactoryFixture factory) : base(factory)
|
public SetpointControllerTest(WebAppFactoryFixture factory) : base(factory)
|
||||||
{
|
{
|
||||||
var scope = factory.Services.CreateScope();
|
var scope = factory.Services.CreateScope();
|
||||||
var httpClient = scope.ServiceProvider
|
var persistenceClientFactory = scope.ServiceProvider
|
||||||
.GetRequiredService<IHttpClientFactory>()
|
.GetRequiredService<PersistenceClientFactory>();
|
||||||
.CreateClient();
|
|
||||||
|
|
||||||
setpointClient = PersistenceClientFactory.GetClient<ISetpointClient>(httpClient);
|
setpointClient = persistenceClientFactory.GetClient<ISetpointClient>();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -17,11 +17,10 @@ public abstract class TimeSeriesBaseControllerTest<TEntity, TDto> : BaseIntegrat
|
|||||||
dbContext.CleanupDbSet<TEntity>();
|
dbContext.CleanupDbSet<TEntity>();
|
||||||
|
|
||||||
var scope = factory.Services.CreateScope();
|
var scope = factory.Services.CreateScope();
|
||||||
var httpClient = scope.ServiceProvider
|
var persistenceClientFactory = scope.ServiceProvider
|
||||||
.GetRequiredService<IHttpClientFactory>()
|
.GetRequiredService<PersistenceClientFactory>();
|
||||||
.CreateClient();
|
|
||||||
|
|
||||||
timeSeriesClient = PersistenceClientFactory.GetClient<ITimeSeriesClient<TDto>>(httpClient);
|
timeSeriesClient = persistenceClientFactory.GetClient<ITimeSeriesClient<TDto>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task InsertRangeSuccess(TDto dto)
|
public async Task InsertRangeSuccess(TDto dto)
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Persistence.IntegrationTests;
|
|
||||||
public class JwtToken
|
|
||||||
{
|
|
||||||
[JsonPropertyName("access_token")]
|
|
||||||
public required string AccessToken { get; set; }
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
namespace Persistence.IntegrationTests;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// настройки credentials для пользователя в KeyCloak
|
|
||||||
/// </summary>
|
|
||||||
public class KeyCloakUser
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public required string Username { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public required string Password { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public required string ClientId { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public required string GrantType { get; set; }
|
|
||||||
}
|
|
@ -3,58 +3,34 @@ using Microsoft.AspNetCore.Mvc.Testing;
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
using Persistence.API;
|
using Persistence.API;
|
||||||
|
using Persistence.Client;
|
||||||
using Persistence.Database.Model;
|
using Persistence.Database.Model;
|
||||||
using Persistence.Database.Postgres;
|
using Persistence.Database.Postgres;
|
||||||
using Refit;
|
|
||||||
using RestSharp;
|
using RestSharp;
|
||||||
using System.Net.Http.Headers;
|
|
||||||
using System.Text.Json;
|
|
||||||
using Persistence.Database.Postgres;
|
|
||||||
using System.Net.Http.Headers;
|
|
||||||
using Persistence.Client;
|
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
|
||||||
|
|
||||||
namespace Persistence.IntegrationTests;
|
namespace Persistence.IntegrationTests;
|
||||||
public class WebAppFactoryFixture : WebApplicationFactory<Startup>
|
public class WebAppFactoryFixture : WebApplicationFactory<Startup>
|
||||||
{
|
{
|
||||||
private static readonly JsonSerializerOptions JsonSerializerOptions = new()
|
private string connectionString = string.Empty;
|
||||||
{
|
|
||||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
|
||||||
PropertyNameCaseInsensitive = true,
|
|
||||||
//Converters = { new ValidationResultConverter() }
|
|
||||||
};
|
|
||||||
|
|
||||||
private static readonly RefitSettings RefitSettings = new(new SystemTextJsonContentSerializer(JsonSerializerOptions));
|
|
||||||
|
|
||||||
private readonly string connectionString;
|
|
||||||
private readonly KeyCloakUser keycloakTestUser;
|
|
||||||
public readonly string KeycloakGetTokenUrl;
|
|
||||||
|
|
||||||
public WebAppFactoryFixture()
|
|
||||||
{
|
|
||||||
var configuration = new ConfigurationBuilder()
|
|
||||||
.AddJsonFile("appsettings.Tests.json")
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
var dbConnection = configuration.GetSection("DbConnection").Get<DbConnection>()!;
|
|
||||||
connectionString = dbConnection.GetConnectionString();
|
|
||||||
|
|
||||||
keycloakTestUser = configuration.GetSection("KeycloakTestUser").Get<KeyCloakUser>()!;
|
|
||||||
|
|
||||||
KeycloakGetTokenUrl = configuration.GetSection("KeycloakGetTokenUrl").Value!;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
||||||
{
|
{
|
||||||
builder.ConfigureServices(services =>
|
builder.ConfigureAppConfiguration((hostingContext, config) =>
|
||||||
|
{
|
||||||
|
config.AddJsonFile("appsettings.Tests.json");
|
||||||
|
|
||||||
|
var dbConnection = config.Build().GetSection("DbConnection").Get<DbConnection>()!;
|
||||||
|
connectionString = dbConnection.GetConnectionString();
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.ConfigureServices(services =>
|
||||||
{
|
{
|
||||||
var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<PersistenceDbContext>));
|
var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<PersistenceDbContext>));
|
||||||
|
|
||||||
if (descriptor != null)
|
if (descriptor != null)
|
||||||
services.Remove(descriptor);
|
services.Remove(descriptor);
|
||||||
|
services.AddDbContext<PersistenceDbContext>(options =>
|
||||||
services.AddDbContext<PersistenceDbContext>(options =>
|
|
||||||
options.UseNpgsql(connectionString));
|
options.UseNpgsql(connectionString));
|
||||||
|
|
||||||
services.RemoveAll<IHttpClientFactory>();
|
services.RemoveAll<IHttpClientFactory>();
|
||||||
@ -63,6 +39,8 @@ public class WebAppFactoryFixture : WebApplicationFactory<Startup>
|
|||||||
return new TestHttpClientFactory(this);
|
return new TestHttpClientFactory(this);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
services.AddSingleton<PersistenceClientFactory>();
|
||||||
|
|
||||||
var serviceProvider = services.BuildServiceProvider();
|
var serviceProvider = services.BuildServiceProvider();
|
||||||
|
|
||||||
using var scope = serviceProvider.CreateScope();
|
using var scope = serviceProvider.CreateScope();
|
||||||
@ -71,7 +49,7 @@ public class WebAppFactoryFixture : WebApplicationFactory<Startup>
|
|||||||
var dbContext = scopedServices.GetRequiredService<PersistenceDbContext>();
|
var dbContext = scopedServices.GetRequiredService<PersistenceDbContext>();
|
||||||
dbContext.Database.EnsureCreatedAndMigrated();
|
dbContext.Database.EnsureCreatedAndMigrated();
|
||||||
dbContext.SaveChanges();
|
dbContext.SaveChanges();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async ValueTask DisposeAsync()
|
public override async ValueTask DisposeAsync()
|
||||||
@ -83,57 +61,4 @@ public class WebAppFactoryFixture : WebApplicationFactory<Startup>
|
|||||||
|
|
||||||
await dbContext.Database.EnsureDeletedAsync();
|
await dbContext.Database.EnsureDeletedAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public T GetHttpClient<T>(string uriSuffix)
|
|
||||||
{
|
|
||||||
var httpClient = CreateClient();
|
|
||||||
if (string.IsNullOrEmpty(uriSuffix))
|
|
||||||
return RestService.For<T>(httpClient, RefitSettings);
|
|
||||||
|
|
||||||
if (httpClient.BaseAddress is not null)
|
|
||||||
httpClient.BaseAddress = new Uri(httpClient.BaseAddress, uriSuffix);
|
|
||||||
|
|
||||||
return RestService.For<T>(httpClient, RefitSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<T> GetAuthorizedHttpClient<T>(string uriSuffix)
|
|
||||||
{
|
|
||||||
var httpClient = await GetAuthorizedHttpClient();
|
|
||||||
if (string.IsNullOrEmpty(uriSuffix))
|
|
||||||
return RestService.For<T>(httpClient, RefitSettings);
|
|
||||||
|
|
||||||
if (httpClient.BaseAddress is not null)
|
|
||||||
httpClient.BaseAddress = new Uri(httpClient.BaseAddress, uriSuffix);
|
|
||||||
|
|
||||||
return RestService.For<T>(httpClient, RefitSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<HttpClient> GetAuthorizedHttpClient()
|
|
||||||
{
|
|
||||||
var httpClient = CreateClient();
|
|
||||||
var token = await GetTokenAsync();
|
|
||||||
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
|
||||||
|
|
||||||
return httpClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<string> GetTokenAsync()
|
|
||||||
{
|
|
||||||
var restClient = new RestClient();
|
|
||||||
|
|
||||||
var request = new RestRequest(KeycloakGetTokenUrl, Method.Post);
|
|
||||||
request.AddParameter("username", keycloakTestUser.Username);
|
|
||||||
request.AddParameter("password", keycloakTestUser.Password);
|
|
||||||
request.AddParameter("client_id", keycloakTestUser.ClientId);
|
|
||||||
request.AddParameter("grant_type", keycloakTestUser.GrantType);
|
|
||||||
|
|
||||||
var keyCloackResponse = await restClient.PostAsync(request);
|
|
||||||
if (keyCloackResponse.IsSuccessful && !String.IsNullOrEmpty(keyCloackResponse.Content))
|
|
||||||
{
|
|
||||||
var token = JsonSerializer.Deserialize<JwtToken>(keyCloackResponse.Content)!;
|
|
||||||
return token.AccessToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
return String.Empty;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
12
Persistence/Models/Configurations/AuthUser.cs
Normal file
12
Persistence/Models/Configurations/AuthUser.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace Persistence.Models.Configurations;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Настройки credentials для авторизации
|
||||||
|
/// </summary>
|
||||||
|
public class AuthUser
|
||||||
|
{
|
||||||
|
public required string Username { get; set; }
|
||||||
|
public required string Password { get; set; }
|
||||||
|
public required string ClientId { get; set; }
|
||||||
|
public required string GrantType { get; set; }
|
||||||
|
}
|
18
Persistence/Models/Configurations/JwtParams.cs
Normal file
18
Persistence/Models/Configurations/JwtParams.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using System.Text;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
namespace Persistence.Models.Configurations
|
||||||
|
{
|
||||||
|
public static class JwtParams
|
||||||
|
{
|
||||||
|
private static readonly string KeyValue = "супер секретный ключ для шифрования";
|
||||||
|
public static SymmetricSecurityKey SecurityKey
|
||||||
|
{
|
||||||
|
get { return new SymmetricSecurityKey(Encoding.ASCII.GetBytes(KeyValue)); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly string Issuer = "a";
|
||||||
|
|
||||||
|
public static readonly string Audience = "a";
|
||||||
|
}
|
||||||
|
}
|
10
Persistence/Models/Configurations/JwtToken.cs
Normal file
10
Persistence/Models/Configurations/JwtToken.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Persistence.Models.Configurations
|
||||||
|
{
|
||||||
|
public class JwtToken
|
||||||
|
{
|
||||||
|
[JsonPropertyName("access_token")]
|
||||||
|
public required string AccessToken { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
|
||||||
|
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.2.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
Loading…
Reference in New Issue
Block a user
Блок кода с if-else c настройками аутентификации для сваггера желательно убрать в отдельный метод