remote service support via Jwt
This commit is contained in:
@ -526,16 +526,12 @@ namespace Oqtane.Controllers
|
||||
public string Token()
|
||||
{
|
||||
var token = "";
|
||||
var user = _users.GetUser(User.Identity.Name);
|
||||
if (user != null)
|
||||
var sitesettings = HttpContext.GetSiteSettings();
|
||||
var secret = sitesettings.GetValue("JwtOptions:Secret", "");
|
||||
if (!string.IsNullOrEmpty(secret))
|
||||
{
|
||||
var sitesettings = HttpContext.GetSiteSettings();
|
||||
var secret = sitesettings.GetValue("JwtOptions:Secret", "");
|
||||
if (!string.IsNullOrEmpty(secret))
|
||||
{
|
||||
var lifetime = 525600; // long-lived token set to 1 year
|
||||
token = _jwtManager.GenerateToken(_tenantManager.GetAlias(), user, secret, sitesettings.GetValue("JwtOptions:Issuer", ""), sitesettings.GetValue("JwtOptions:Audience", ""), lifetime);
|
||||
}
|
||||
var lifetime = 525600; // long-lived token set to 1 year
|
||||
token = _jwtManager.GenerateToken(_tenantManager.GetAlias(), (ClaimsIdentity)User.Identity, secret, sitesettings.GetValue("JwtOptions:Issuer", ""), sitesettings.GetValue("JwtOptions:Audience", ""), lifetime);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
@ -548,7 +544,10 @@ namespace Oqtane.Controllers
|
||||
if (user.IsAuthenticated)
|
||||
{
|
||||
user.Username = User.Identity.Name;
|
||||
user.UserId = int.Parse(User.Claims.First(item => item.Type == ClaimTypes.PrimarySid).Value);
|
||||
if (User.HasClaim(item => item.Type == ClaimTypes.NameIdentifier))
|
||||
{
|
||||
user.UserId = int.Parse(User.Claims.First(item => item.Type == ClaimTypes.NameIdentifier).Value);
|
||||
}
|
||||
string roles = "";
|
||||
foreach (var claim in User.Claims.Where(item => item.Type == ClaimTypes.Role))
|
||||
{
|
||||
|
@ -194,7 +194,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||
return services;
|
||||
}
|
||||
|
||||
internal static IServiceCollection TryAddHttpClientWithAuthenticationCookie(this IServiceCollection services)
|
||||
internal static IServiceCollection AddHttpClients(this IServiceCollection services)
|
||||
{
|
||||
if (!services.Any(x => x.ServiceType == typeof(HttpClient)))
|
||||
{
|
||||
@ -216,6 +216,8 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||
});
|
||||
}
|
||||
|
||||
services.AddHttpClient("External");
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
{
|
||||
@(Html.AntiForgeryToken())
|
||||
|
||||
<component type="typeof(Oqtane.App)" render-mode="@Model.RenderMode" param-AntiForgeryToken="@Model.AntiForgeryToken" param-Runtime="@Model.Runtime" param-RenderMode="@Model.RenderMode.ToString()" param-VisitorId="@Model.VisitorId" param-RemoteIPAddress="@Model.RemoteIPAddress" />
|
||||
<component type="typeof(Oqtane.App)" render-mode="@Model.RenderMode" param-AntiForgeryToken="@Model.AntiForgeryToken" param-Runtime="@Model.Runtime" param-RenderMode="@Model.RenderMode.ToString()" param-VisitorId="@Model.VisitorId" param-RemoteIPAddress="@Model.RemoteIPAddress" param-AuthorizationToken="@Model.AuthorizationToken" />
|
||||
|
||||
<div id="blazor-error-ui">
|
||||
<environment include="Staging,Production">
|
||||
|
@ -20,6 +20,8 @@ using System.Security.Claims;
|
||||
using System.Net;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Oqtane.Enums;
|
||||
using Oqtane.Security;
|
||||
using Oqtane.Extensions;
|
||||
|
||||
namespace Oqtane.Pages
|
||||
{
|
||||
@ -30,6 +32,7 @@ namespace Oqtane.Pages
|
||||
private readonly ILocalizationManager _localizationManager;
|
||||
private readonly ILanguageRepository _languages;
|
||||
private readonly IAntiforgery _antiforgery;
|
||||
private readonly IJwtManager _jwtManager;
|
||||
private readonly ISiteRepository _sites;
|
||||
private readonly IPageRepository _pages;
|
||||
private readonly IUrlMappingRepository _urlMappings;
|
||||
@ -38,13 +41,14 @@ namespace Oqtane.Pages
|
||||
private readonly ISettingRepository _settings;
|
||||
private readonly ILogManager _logger;
|
||||
|
||||
public HostModel(IConfigManager configuration, ITenantManager tenantManager, ILocalizationManager localizationManager, ILanguageRepository languages, IAntiforgery antiforgery, ISiteRepository sites, IPageRepository pages, IUrlMappingRepository urlMappings, IVisitorRepository visitors, IAliasRepository aliases, ISettingRepository settings, ILogManager logger)
|
||||
public HostModel(IConfigManager configuration, ITenantManager tenantManager, ILocalizationManager localizationManager, ILanguageRepository languages, IAntiforgery antiforgery, IJwtManager jwtManager, ISiteRepository sites, IPageRepository pages, IUrlMappingRepository urlMappings, IVisitorRepository visitors, IAliasRepository aliases, ISettingRepository settings, ILogManager logger)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_tenantManager = tenantManager;
|
||||
_localizationManager = localizationManager;
|
||||
_languages = languages;
|
||||
_antiforgery = antiforgery;
|
||||
_jwtManager = jwtManager;
|
||||
_sites = sites;
|
||||
_pages = pages;
|
||||
_urlMappings = urlMappings;
|
||||
@ -56,6 +60,7 @@ namespace Oqtane.Pages
|
||||
|
||||
public string Language = "en";
|
||||
public string AntiForgeryToken = "";
|
||||
public string AuthorizationToken = "";
|
||||
public string Runtime = "Server";
|
||||
public RenderMode RenderMode = RenderMode.Server;
|
||||
public int VisitorId = -1;
|
||||
@ -133,6 +138,17 @@ namespace Oqtane.Pages
|
||||
Title = site.Name;
|
||||
ThemeType = site.DefaultThemeType;
|
||||
|
||||
// get jwt token for downstream APIs
|
||||
if (User.Identity.IsAuthenticated)
|
||||
{
|
||||
var sitesettings = HttpContext.GetSiteSettings();
|
||||
var secret = sitesettings.GetValue("JwtOptions:Secret", "");
|
||||
if (!string.IsNullOrEmpty(secret))
|
||||
{
|
||||
AuthorizationToken = _jwtManager.GenerateToken(alias, (ClaimsIdentity)User.Identity, secret, sitesettings.GetValue("JwtOptions:Issuer", ""), sitesettings.GetValue("JwtOptions:Audience", ""), int.Parse(sitesettings.GetValue("JwtOptions:Lifetime", "20")));
|
||||
}
|
||||
}
|
||||
|
||||
if (site.VisitorTracking)
|
||||
{
|
||||
TrackVisitor(site.SiteId);
|
||||
@ -247,9 +263,9 @@ namespace Oqtane.Pages
|
||||
string url = Request.GetEncodedUrl();
|
||||
string referrer = (Request.Headers[HeaderNames.Referer] != StringValues.Empty) ? Request.Headers[HeaderNames.Referer] : "";
|
||||
int? userid = null;
|
||||
if (User.HasClaim(item => item.Type == ClaimTypes.PrimarySid))
|
||||
if (User.HasClaim(item => item.Type == ClaimTypes.NameIdentifier))
|
||||
{
|
||||
userid = int.Parse(User.Claims.First(item => item.Type == ClaimTypes.PrimarySid).Value);
|
||||
userid = int.Parse(User.Claims.First(item => item.Type == ClaimTypes.NameIdentifier).Value);
|
||||
}
|
||||
|
||||
// check if cookie already exists
|
||||
|
@ -10,20 +10,19 @@ namespace Oqtane.Security
|
||||
{
|
||||
public interface IJwtManager
|
||||
{
|
||||
string GenerateToken(Alias alias, User user, string secret, string issuer, string audience, int lifetime);
|
||||
string GenerateToken(Alias alias, ClaimsIdentity user, string secret, string issuer, string audience, int lifetime);
|
||||
User ValidateToken(string token, string secret, string issuer, string audience);
|
||||
}
|
||||
|
||||
public class JwtManager : IJwtManager
|
||||
{
|
||||
public string GenerateToken(Alias alias, User user, string secret, string issuer, string audience, int lifetime)
|
||||
public string GenerateToken(Alias alias, ClaimsIdentity user, string secret, string issuer, string audience, int lifetime)
|
||||
{
|
||||
var tokenHandler = new JwtSecurityTokenHandler();
|
||||
var key = Encoding.ASCII.GetBytes(secret);
|
||||
var identity = UserSecurity.CreateClaimsIdentity(alias, user);
|
||||
var tokenDescriptor = new SecurityTokenDescriptor
|
||||
{
|
||||
Subject = new ClaimsIdentity(identity),
|
||||
Subject = new ClaimsIdentity(user),
|
||||
Issuer = issuer,
|
||||
Audience = audience,
|
||||
Expires = DateTime.UtcNow.AddMinutes(lifetime),
|
||||
@ -56,7 +55,7 @@ namespace Oqtane.Security
|
||||
var jwtToken = (JwtSecurityToken)validatedToken;
|
||||
var user = new User
|
||||
{
|
||||
UserId = int.Parse(jwtToken.Claims.FirstOrDefault(item => item.Type == "id")?.Value),
|
||||
UserId = int.Parse(jwtToken.Claims.FirstOrDefault(item => item.Type == "nameid")?.Value),
|
||||
Username = jwtToken.Claims.FirstOrDefault(item => item.Type == "name")?.Value
|
||||
};
|
||||
return user;
|
||||
|
@ -28,7 +28,7 @@ namespace Oqtane.Security
|
||||
var claims = context.Principal.Claims;
|
||||
|
||||
// check if principal has roles and matches current site
|
||||
if (!claims.Any(item => item.Type == ClaimTypes.Role) || claims.FirstOrDefault(item => item.Type == ClaimTypes.GroupSid)?.Value != alias.SiteKey)
|
||||
if (!claims.Any(item => item.Type == ClaimTypes.Role) || claims.FirstOrDefault(item => item.Type == "sitekey")?.Value != alias.SiteKey)
|
||||
{
|
||||
var userRepository = context.HttpContext.RequestServices.GetService(typeof(IUserRepository)) as IUserRepository;
|
||||
var userRoleRepository = context.HttpContext.RequestServices.GetService(typeof(IUserRoleRepository)) as IUserRoleRepository;
|
||||
|
@ -49,9 +49,9 @@ namespace Oqtane.Security
|
||||
if (user.IsAuthenticated)
|
||||
{
|
||||
user.Username = principal.Identity.Name;
|
||||
if (principal.Claims.Any(item => item.Type == ClaimTypes.PrimarySid))
|
||||
if (principal.Claims.Any(item => item.Type == ClaimTypes.NameIdentifier))
|
||||
{
|
||||
user.UserId = int.Parse(principal.Claims.First(item => item.Type == ClaimTypes.PrimarySid).Value);
|
||||
user.UserId = int.Parse(principal.Claims.First(item => item.Type == ClaimTypes.NameIdentifier).Value);
|
||||
}
|
||||
foreach (var claim in principal.Claims.Where(item => item.Type == ClaimTypes.Role))
|
||||
{
|
||||
|
@ -70,7 +70,7 @@ namespace Oqtane
|
||||
});
|
||||
|
||||
// setup HttpClient for server side in a client side compatible fashion ( with auth cookie )
|
||||
services.TryAddHttpClientWithAuthenticationCookie();
|
||||
services.AddHttpClients();
|
||||
|
||||
// register scoped core services
|
||||
services.AddScoped<IAuthorizationHandler, PermissionHandler>()
|
||||
|
BIN
Oqtane.Server/wwwroot/Modules/Oqtane.Showcase/screenshot.png
Normal file
BIN
Oqtane.Server/wwwroot/Modules/Oqtane.Showcase/screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
Reference in New Issue
Block a user