OpenAuthImplementStarted
This commit is contained in:
parent
65b924c174
commit
d332cd0d96
|
@ -0,0 +1,159 @@
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Text.Json.Serialization;
|
||||
using Yuna.Website.Server.Infrastructure;
|
||||
using Yuna.Website.Server.Services.OpenAuthService;
|
||||
|
||||
namespace Yuna.Website.Server.API
|
||||
{
|
||||
public class OpenAuthEndpoints
|
||||
{
|
||||
public void Define(WebApplication app)
|
||||
{
|
||||
app.MapGet("~/.well-known/openid-configuration", GetConfiguration);
|
||||
|
||||
app.MapMethods("/v1.0", ["HEAD"], Ping);
|
||||
|
||||
app.MapGet("api/oauth/login", LoginViaOauth);
|
||||
}
|
||||
|
||||
public class DiscoveryResponse
|
||||
{
|
||||
[JsonPropertyName("issuer")]
|
||||
public string? Issuer { get; set; }
|
||||
|
||||
[JsonPropertyName("authorization_endpoint")]
|
||||
public string? AuthorizationEndpoint { get; set; }
|
||||
|
||||
[JsonPropertyName("token_endpoint")]
|
||||
public string? TokenEndpoint { get; set; }
|
||||
|
||||
[JsonPropertyName("token_endpoint_auth_methods_supported")]
|
||||
public IList<string>? TokenEndpointAuthMethodsSupported { get; set; }
|
||||
|
||||
[JsonPropertyName("token_endpoint_auth_signing_alg_values_supported")]
|
||||
public IList<string>? TokenEndpointAuthSigningAlgValuesSupported { get; set; }
|
||||
|
||||
[JsonPropertyName("userinfo_endpoint")]
|
||||
public string? UserinfoEndpoint { get; set; }
|
||||
|
||||
[JsonPropertyName("check_session_iframe")]
|
||||
public string? CheckSessionIframe { get; set; }
|
||||
|
||||
[JsonPropertyName("end_session_endpoint")]
|
||||
public string? EndSessionEndpoint { get; set; }
|
||||
|
||||
[JsonPropertyName("jwks_uri")]
|
||||
public string? JwksUri { get; set; }
|
||||
|
||||
[JsonPropertyName("registration_endpoint")]
|
||||
public string? RegistrationEndpoint { get; set; }
|
||||
|
||||
[JsonPropertyName("scopes_supported")]
|
||||
public IList<string>? ScopesSupported { get; set; }
|
||||
|
||||
[JsonPropertyName("response_types_supported")]
|
||||
public IList<string>? ResponseTypesSupported { get; set; }
|
||||
|
||||
[JsonPropertyName("acr_values_supported")]
|
||||
public IList<string>? AcrValuesSupported { get; set; }
|
||||
|
||||
[JsonPropertyName("subject_types_supported")]
|
||||
public IList<string>? SubjectTypesSupported { get; set; }
|
||||
|
||||
[JsonPropertyName("userinfo_signing_alg_values_supported")]
|
||||
public IList<string>? UserinfoSigningAlgValuesSupported { get; set; }
|
||||
|
||||
[JsonPropertyName("userinfo_encryption_alg_values_supported")]
|
||||
public IList<string>? UserinfoEncryptionAlgValuesSupported { get; set; }
|
||||
|
||||
[JsonPropertyName("userinfo_encryption_enc_values_supported")]
|
||||
public IList<string>? UserinfoEncryptionEncValuesSupported { get; set; }
|
||||
|
||||
[JsonPropertyName("id_token_signing_alg_values_supported")]
|
||||
public IList<string>? IdTokenSigningAlgValuesSupported { get; set; }
|
||||
|
||||
[JsonPropertyName("id_token_encryption_alg_values_supported")]
|
||||
public IList<string>? IdTokenEncryptionAlgValuesSupported { get; set; }
|
||||
|
||||
[JsonPropertyName("id_token_encryption_enc_values_supported")]
|
||||
public IList<string>? IdTokenEncryptionEncValuesSupported { get; set; }
|
||||
|
||||
[JsonPropertyName("request_object_signing_alg_values_supported")]
|
||||
public IList<string>? RequestObjectSigningAlgValuesSupported { get; set; }
|
||||
|
||||
[JsonPropertyName("display_values_supported")]
|
||||
public IList<string>? DisplayValuesSupported { get; set; }
|
||||
|
||||
[JsonPropertyName("claim_types_supported")]
|
||||
public IList<string>? ClaimTypesSupported { get; set; }
|
||||
|
||||
[JsonPropertyName("claims_supported")]
|
||||
public IList<string>? ClaimsSupported { get; set; }
|
||||
|
||||
[JsonPropertyName("claims_parameter_supported")]
|
||||
public bool? ClaimsParameterSupported { get; set; }
|
||||
|
||||
[JsonPropertyName("service_documentation")]
|
||||
public string? ServiceDocumentation { get; set; }
|
||||
|
||||
[JsonPropertyName("ui_locales_supported")]
|
||||
public IList<string>? UiLocalesSupported { get; set; }
|
||||
}
|
||||
|
||||
public IResult GetConfiguration()
|
||||
{
|
||||
var response = new DiscoveryResponse()
|
||||
{
|
||||
Issuer = Settings.HttpsExternalUrl,
|
||||
AuthorizationEndpoint = Settings.HttpsExternalUrl + "/makaka",
|
||||
TokenEndpoint = Settings.HttpsExternalUrl + "/token",
|
||||
TokenEndpointAuthMethodsSupported = ["client_secret_basic", "private_key_jwt"],
|
||||
TokenEndpointAuthSigningAlgValuesSupported = ["RS256", "ES256"],
|
||||
|
||||
AcrValuesSupported = ["urn:mace:incommon:iap:silver", "urn:mace:incommon:iap:bronze"],
|
||||
ResponseTypesSupported = ["code", "code id_token", "id_token", "token id_token"],
|
||||
SubjectTypesSupported = [],
|
||||
|
||||
UserinfoEncryptionEncValuesSupported = ["A128CBC-HS256", "A128GCM"],
|
||||
IdTokenSigningAlgValuesSupported = ["RS256", "ES256", "HS256"],
|
||||
IdTokenEncryptionAlgValuesSupported = ["RSA1_5", "A128KW"],
|
||||
IdTokenEncryptionEncValuesSupported = ["A128CBC-HS256", "A128GCM"],
|
||||
|
||||
RequestObjectSigningAlgValuesSupported = ["none", "RS256", "ES256"],
|
||||
DisplayValuesSupported = ["page", "popup"],
|
||||
ClaimTypesSupported = ["normal", "distributed"],
|
||||
|
||||
|
||||
ScopesSupported = [],
|
||||
ClaimsSupported = [],
|
||||
ClaimsParameterSupported = false,
|
||||
ServiceDocumentation = null,
|
||||
UiLocalesSupported = ["ru-RU"],
|
||||
|
||||
};
|
||||
|
||||
return Results.Json(response);
|
||||
}
|
||||
|
||||
public IResult Ping()
|
||||
{
|
||||
return Results.Ok();
|
||||
}
|
||||
|
||||
public IResult LoginViaOauth(
|
||||
[FromQuery] string state,
|
||||
[FromQuery] string redirect_uri,
|
||||
[FromQuery]string response_type,
|
||||
[FromQuery]string client_id, HttpContext context,
|
||||
IOpenAuthService openAuthService)
|
||||
{
|
||||
|
||||
var host = context.Request.Host;
|
||||
if (!openAuthService.ValidateLoginRequest(response_type, client_id, host.Value))
|
||||
return Results.Unauthorized();
|
||||
|
||||
//TODO LOGIN PAGE URL IN SETTINGS
|
||||
return Results.Redirect($"https://localhost:5173/login?redirect_to={redirect_uri}");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,8 @@
|
|||
"AppVariables": {
|
||||
"AccessTokenLifeTimeMinutes": 1,
|
||||
"RefreshTokenLifeTimeDays": 365,
|
||||
"ReferalCode": "#I_@m_g00d_guy_07_07_2024"
|
||||
"ReferalCode": "#I_@m_g00d_guy_07_07_2024",
|
||||
"HttpsExternalHost": "https://smarthome.vasich.keenetic.pro"
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"BarcodeService": "http://localhost:7799/barcode",
|
||||
|
|
|
@ -27,5 +27,13 @@ namespace Yuna.Website.Server.Infrastructure
|
|||
var hashedSalt = _tokenHasher.ComputeHash(bytesStr);
|
||||
return Convert.ToBase64String(hashedSalt);
|
||||
}
|
||||
|
||||
public static string GenerateRandomString(int length)
|
||||
{
|
||||
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
Random random = new Random();
|
||||
return new string(Enumerable.Repeat(chars, length)
|
||||
.Select(s => s[random.Next(s.Length)]).ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ namespace Yuna.Website.Server.Infrastructure
|
|||
public static string ReferalCode { get; private set; } = null!;
|
||||
public static string DbConnectionStr { get; private set; } = null!;
|
||||
|
||||
public static string HttpsExternalUrl { get; private set; } = null!;
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
var jsonText = File.ReadAllText("globalSettings.json");
|
||||
|
@ -50,6 +52,7 @@ namespace Yuna.Website.Server.Infrastructure
|
|||
|
||||
private static void LoadAppVariables(JsonElement appVariablesStr)
|
||||
{
|
||||
HttpsExternalUrl = appVariablesStr.GetProperty("HttpsExternalHost").GetString() ?? throw new Exception("no https exernal host");
|
||||
ReferalCode = appVariablesStr.GetProperty("ReferalCode").GetString() ?? throw new Exception("No ref code");
|
||||
AccessTokenLifeTime = TimeSpan.FromSeconds(appVariablesStr.GetProperty("AccessTokenLifeTimeMinutes").GetInt32());
|
||||
RefreshTokenLifeTime = TimeSpan.FromDays(appVariablesStr.GetProperty("RefreshTokenLifeTimeDays").GetInt32());
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
namespace Yuna.Website.Server.Model
|
||||
{
|
||||
public class UserBinding
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long UserId { get; set; }
|
||||
public string Code { get; set; } = null!;
|
||||
public string AccessToken { get; set; } = null!;
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@
|
|||
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy"
|
||||
},
|
||||
"dotnetRunMessages": true,
|
||||
"applicationUrl": "http://localhost:5227"
|
||||
"applicationUrl": "http://192.168.1.2:5227"
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
|
@ -28,6 +28,17 @@
|
|||
"ASPNETCORE_HTTP_PORTS": "8080"
|
||||
},
|
||||
"publishAllPorts": true
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy"
|
||||
},
|
||||
"dotnetRunMessages": true,
|
||||
"applicationUrl": "https://192.168.1.2:5227"
|
||||
}
|
||||
},
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
|
@ -39,4 +50,4 @@
|
|||
"sslPort": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
using Yuna.Website.Server.Model;
|
||||
|
||||
namespace Yuna.Website.Server.Services.OpenAuthService
|
||||
{
|
||||
public interface IOpenAuthService
|
||||
{
|
||||
public bool ValidateLoginRequest(string responseType, string clientId, string host);
|
||||
public UserBinding CreateBinding(User user);
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
using Yuna.Website.Server.Infrastructure;
|
||||
using Yuna.Website.Server.Model;
|
||||
using Yuna.Website.Server.Storage.Repositories.UserBindings;
|
||||
|
||||
namespace Yuna.Website.Server.Services.OpenAuthService
|
||||
{
|
||||
public class OpenAuthService : IOpenAuthService
|
||||
{
|
||||
private readonly IUserBindingsRepository _userBindingsRepository;
|
||||
private readonly ILogger<OpenAuthService> _logger;
|
||||
public OpenAuthService(IUserBindingsRepository userBindingsRepository, ILogger<OpenAuthService> logger)
|
||||
{
|
||||
_userBindingsRepository = userBindingsRepository;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public UserBinding CreateBinding(User user)
|
||||
{
|
||||
//Надо переделать, чтобы код и токен точно были уникальные
|
||||
var binding = new UserBinding()
|
||||
{
|
||||
AccessToken = Encrypter.GenerateRandomString(128),
|
||||
Code = Encrypter.GenerateRandomString(50),
|
||||
UserId = user.Id
|
||||
};
|
||||
|
||||
_logger.LogInformation("Created OauthBinding:\n" +
|
||||
"UserId: {0}\n" +
|
||||
"AccessToken: {1}\n" +
|
||||
"Code: {2}\n", user.Id, binding.Code, binding.AccessToken);
|
||||
|
||||
return _userBindingsRepository.Create(binding);
|
||||
}
|
||||
|
||||
public bool ValidateLoginRequest(string responseType, string clientId, string host)
|
||||
{
|
||||
_logger.LogInformation("Host: {0}", host);
|
||||
|
||||
var result = responseType.Equals("code") && clientId.Equals("vasich_yandex_server");
|
||||
|
||||
if (result) _logger.LogInformation("OauthRequest valid");
|
||||
else _logger.LogWarning("OauthRequest invalid");
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,12 +3,14 @@ using Yuna.Website.Server.API;
|
|||
using Yuna.Website.Server.Infrastructure;
|
||||
using Yuna.Website.Server.Services.DeviceService;
|
||||
using Yuna.Website.Server.Services.DeviceSkillService;
|
||||
using Yuna.Website.Server.Services.OpenAuthService;
|
||||
using Yuna.Website.Server.Services.TokenService;
|
||||
using Yuna.Website.Server.Services.UserService;
|
||||
using Yuna.Website.Server.Storage;
|
||||
using Yuna.Website.Server.Storage.Repositories.Device;
|
||||
using Yuna.Website.Server.Storage.Repositories.Prop;
|
||||
using Yuna.Website.Server.Storage.Repositories.User;
|
||||
using Yuna.Website.Server.Storage.Repositories.UserBindings;
|
||||
|
||||
namespace Yuna.Website.Server
|
||||
{
|
||||
|
@ -60,6 +62,7 @@ namespace Yuna.Website.Server
|
|||
|
||||
public static void DefineEndpoints(WebApplication app)
|
||||
{
|
||||
new OpenAuthEndpoints().Define(app);
|
||||
new AuthEndpoints().Define(app);
|
||||
new SkillsEndpoints().Define(app);
|
||||
new DeviceEndpoints().Define(app);
|
||||
|
@ -129,10 +132,13 @@ namespace Yuna.Website.Server
|
|||
builder.Services.AddScoped<IPropService, PropService>();
|
||||
builder.Services.AddScoped<ITokenService, TokenService>();
|
||||
builder.Services.AddScoped<IDeviceService, DeviceService>();
|
||||
builder.Services.AddScoped<IOpenAuthService, OpenAuthService>();
|
||||
|
||||
|
||||
builder.Services.AddScoped<IDeviceRepository, DeviceRepository>();
|
||||
builder.Services.AddScoped<IPropRepository, PropRepository>();
|
||||
builder.Services.AddScoped<IUserRepository, UserRepository>();
|
||||
builder.Services.AddScoped<IUserBindingsRepository, UserBindingRepository>();
|
||||
}
|
||||
|
||||
public static void DefineAuth(WebApplicationBuilder builder)
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
using Yuna.Website.Server.Model;
|
||||
|
||||
namespace Yuna.Website.Server.Storage.Repositories.UserBindings
|
||||
{
|
||||
public interface IUserBindingsRepository
|
||||
{
|
||||
public UserBinding? GetUserBinding(string code);
|
||||
public UserBinding Create(UserBinding userBinding);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using Yuna.Website.Server.Model;
|
||||
|
||||
namespace Yuna.Website.Server.Storage.Repositories.UserBindings
|
||||
{
|
||||
public class UserBindingRepository : IUserBindingsRepository
|
||||
{
|
||||
private static List<UserBinding> _inMemoryContext = new();
|
||||
|
||||
public UserBindingRepository() { }
|
||||
|
||||
public UserBinding Create(UserBinding userBinding)
|
||||
{
|
||||
userBinding.Id = _inMemoryContext.Count;
|
||||
_inMemoryContext.Add(userBinding);
|
||||
return userBinding;
|
||||
}
|
||||
|
||||
public UserBinding? GetUserBinding(string code)
|
||||
{
|
||||
var binding = _inMemoryContext.FirstOrDefault(x => x.Code.Equals(code));
|
||||
return binding;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import axios from "axios";
|
||||
|
||||
export const api = axios.create({
|
||||
baseURL: "http://localhost:5227/api/",
|
||||
baseURL: "https://192.168.1.2:5227/api/",
|
||||
validateStatus: (status) => status < 500,
|
||||
withCredentials: true,
|
||||
headers: { 'Accept': 'application/json' }
|
||||
|
|
Loading…
Reference in New Issue