mirror of https://github.com/abpframework/abp.git
42 changed files with 645 additions and 47 deletions
@ -0,0 +1,56 @@ |
|||||
|
using System; |
||||
|
using IdentityModel.Client; |
||||
|
using Microsoft.AspNetCore.Authentication.OpenIdConnect; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
|
||||
|
namespace Microsoft.AspNetCore.Authentication.Cookies; |
||||
|
|
||||
|
public static class CookieAuthenticationOptionsExtensions |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Introspect access token on validating the principal.
|
||||
|
/// </summary>
|
||||
|
/// <param name="options"></param>
|
||||
|
/// <param name="oidcAuthenticationScheme"></param>
|
||||
|
/// <returns></returns>
|
||||
|
public static CookieAuthenticationOptions IntrospectAccessToken(this CookieAuthenticationOptions options, string oidcAuthenticationScheme = "oidc") |
||||
|
{ |
||||
|
var originalHandler = options.Events.OnValidatePrincipal; |
||||
|
options.Events.OnValidatePrincipal = async principalContext => |
||||
|
{ |
||||
|
originalHandler?.Invoke(principalContext); |
||||
|
|
||||
|
if (principalContext.Principal != null && principalContext.Principal.Identity != null && principalContext.Principal.Identity.IsAuthenticated) |
||||
|
{ |
||||
|
var accessToken = principalContext.Properties.GetTokenValue("access_token"); |
||||
|
if (!accessToken.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
var openIdConnectOptions = principalContext.HttpContext.RequestServices.GetRequiredService<IOptionsMonitor<OpenIdConnectOptions>>().Get(oidcAuthenticationScheme); |
||||
|
if (openIdConnectOptions.Configuration == null && openIdConnectOptions.ConfigurationManager != null) |
||||
|
{ |
||||
|
openIdConnectOptions.Configuration = await openIdConnectOptions.ConfigurationManager.GetConfigurationAsync(principalContext.HttpContext.RequestAborted); |
||||
|
} |
||||
|
|
||||
|
var response = await openIdConnectOptions.Backchannel.IntrospectTokenAsync(new TokenIntrospectionRequest |
||||
|
{ |
||||
|
Address = openIdConnectOptions.Configuration?.IntrospectionEndpoint ?? openIdConnectOptions.Authority.EnsureEndsWith('/') + "connect/introspect", |
||||
|
ClientId = openIdConnectOptions.ClientId, |
||||
|
ClientSecret = openIdConnectOptions.ClientSecret, |
||||
|
Token = accessToken |
||||
|
}); |
||||
|
|
||||
|
if (response.IsActive) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
principalContext.RejectPrincipal(); |
||||
|
await principalContext.HttpContext.SignOutAsync(principalContext.Scheme.Name); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
return options; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.AspNetCore.Components.Web.Configuration; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.WebAssembly.Configuration; |
||||
|
|
||||
|
[Dependency(ReplaceServices = true)] |
||||
|
public class BlazorWebAssemblyCurrentApplicationConfigurationCacheResetService : |
||||
|
ICurrentApplicationConfigurationCacheResetService, |
||||
|
ITransientDependency |
||||
|
{ |
||||
|
private readonly WebAssemblyCachedApplicationConfigurationClient _webAssemblyCachedApplicationConfigurationClient; |
||||
|
|
||||
|
public BlazorWebAssemblyCurrentApplicationConfigurationCacheResetService(WebAssemblyCachedApplicationConfigurationClient webAssemblyCachedApplicationConfigurationClient) |
||||
|
{ |
||||
|
_webAssemblyCachedApplicationConfigurationClient = webAssemblyCachedApplicationConfigurationClient; |
||||
|
} |
||||
|
|
||||
|
public async Task ResetAsync() |
||||
|
{ |
||||
|
await _webAssemblyCachedApplicationConfigurationClient.InitializeAsync(); |
||||
|
} |
||||
|
} |
||||
@ -1,16 +1,28 @@ |
|||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||
|
using Microsoft.Extensions.Options; |
||||
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
||||
using Volo.Abp.AspNetCore.Mvc.UI.Packages.Core; |
using Volo.Abp.AspNetCore.Mvc.UI.Packages.Core; |
||||
using Volo.Abp.Modularity; |
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Select2; |
namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Select2; |
||||
|
|
||||
[DependsOn(typeof(CoreScriptContributor))] |
[DependsOn(typeof(CoreScriptContributor))] |
||||
public class Select2ScriptContributor : BundleContributor |
public class Select2ScriptContributor : BundleContributor |
||||
{ |
{ |
||||
|
public const string PackageName = "select2"; |
||||
public override void ConfigureBundle(BundleConfigurationContext context) |
public override void ConfigureBundle(BundleConfigurationContext context) |
||||
{ |
{ |
||||
//TODO: Add select2.full.min.js or localize!
|
//TODO: Add select2.full.min.js
|
||||
context.Files.AddIfNotContains("/libs/select2/js/select2.min.js"); |
context.Files.AddIfNotContains("/libs/select2/js/select2.min.js"); |
||||
} |
} |
||||
|
public override void ConfigureDynamicResources(BundleConfigurationContext context) |
||||
|
{ |
||||
|
var fileName = context.LazyServiceProvider.LazyGetRequiredService<IOptions<AbpLocalizationOptions>>().Value.GetCurrentUICultureLanguageFilesMap(PackageName); |
||||
|
var filePath = $"/libs/select2/js/i18n/{fileName}.js"; |
||||
|
if (context.FileProvider.GetFileInfo(filePath).Exists) |
||||
|
{ |
||||
|
context.Files.AddIfNotContains(filePath); |
||||
|
} |
||||
|
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,67 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.UI.Navigation; |
||||
|
|
||||
|
public class ApplicationMenuGroup |
||||
|
{ |
||||
|
private string _displayName; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Default <see cref="Order"/> value of a group item.
|
||||
|
/// </summary>
|
||||
|
public const int DefaultOrder = 1000; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Unique name of the group in the application.
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
public string Name { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Display name of the group.
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
public string DisplayName { |
||||
|
get { return _displayName; } |
||||
|
set { |
||||
|
Check.NotNullOrWhiteSpace(value, nameof(value)); |
||||
|
_displayName = value; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Can be used to render the element with a specific Id for DOM selections.
|
||||
|
/// </summary>
|
||||
|
public string ElementId { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The Display order of the group.
|
||||
|
/// Default value: 1000.
|
||||
|
/// </summary>
|
||||
|
public int Order { get; set; } |
||||
|
|
||||
|
public ApplicationMenuGroup( |
||||
|
[NotNull] string name, |
||||
|
[NotNull] string displayName, |
||||
|
string elementId = null, |
||||
|
int order = DefaultOrder) |
||||
|
{ |
||||
|
Check.NotNullOrWhiteSpace(name, nameof(name)); |
||||
|
Check.NotNullOrWhiteSpace(displayName, nameof(displayName)); |
||||
|
|
||||
|
Name = name; |
||||
|
DisplayName = displayName; |
||||
|
ElementId = elementId; |
||||
|
Order = order; |
||||
|
} |
||||
|
|
||||
|
private string GetDefaultElementId() |
||||
|
{ |
||||
|
return "MenuGroup_" + Name; |
||||
|
} |
||||
|
|
||||
|
public override string ToString() |
||||
|
{ |
||||
|
return $"[ApplicationMenuGroup] Name = {Name}"; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,36 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
|
||||
|
namespace Volo.Abp.UI.Navigation; |
||||
|
|
||||
|
public class ApplicationMenuGroupList: List<ApplicationMenuGroup> |
||||
|
{ |
||||
|
public ApplicationMenuGroupList() |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public ApplicationMenuGroupList(int capacity) |
||||
|
: base(capacity) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public ApplicationMenuGroupList(IEnumerable<ApplicationMenuGroup> collection) |
||||
|
: base(collection) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public void Normalize() |
||||
|
{ |
||||
|
Order(); |
||||
|
} |
||||
|
|
||||
|
private void Order() |
||||
|
{ |
||||
|
var orderedItems = this.OrderBy(item => item.Order).ToArray(); |
||||
|
Clear(); |
||||
|
AddRange(orderedItems); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
namespace Volo.Abp.UI.Navigation; |
||||
|
|
||||
|
public interface IHasMenuGroups |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Menu groups.
|
||||
|
/// </summary>
|
||||
|
ApplicationMenuGroupList Groups { get; } |
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
import { Injectable } from '@angular/core'; |
||||
|
|
||||
|
@Injectable({ |
||||
|
providedIn: 'root', |
||||
|
}) |
||||
|
export class AbpLocalStorageService implements Storage { |
||||
|
constructor() {} |
||||
|
[name: string]: any; |
||||
|
get length(): number { |
||||
|
return localStorage.length; |
||||
|
} |
||||
|
|
||||
|
clear(): void { |
||||
|
localStorage.clear(); |
||||
|
} |
||||
|
getItem(key: string): string { |
||||
|
return localStorage.getItem(key); |
||||
|
} |
||||
|
key(index: number): string { |
||||
|
return localStorage.key(index); |
||||
|
} |
||||
|
removeItem(key: string): void { |
||||
|
localStorage.removeItem(key); |
||||
|
} |
||||
|
setItem(key: string, value: string): void { |
||||
|
localStorage.setItem(key, value); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,52 @@ |
|||||
|
import { TestBed } from '@angular/core/testing'; |
||||
|
|
||||
|
import { AbpLocalStorageService } from '../services/local-storage.service'; |
||||
|
|
||||
|
describe('LocalStorageService', () => { |
||||
|
let service: AbpLocalStorageService; |
||||
|
|
||||
|
beforeEach(() => { |
||||
|
TestBed.configureTestingModule({}); |
||||
|
service = TestBed.inject(AbpLocalStorageService); |
||||
|
}); |
||||
|
|
||||
|
it('should be created', () => { |
||||
|
expect(service).toBeTruthy(); |
||||
|
}); |
||||
|
|
||||
|
it('should be called getItem', () => { |
||||
|
const spy = jest.spyOn(service, 'getItem'); |
||||
|
service.getItem('test'); |
||||
|
expect(spy).toHaveBeenCalled(); |
||||
|
}); |
||||
|
|
||||
|
it('should be called setItem', () => { |
||||
|
const spy = jest.spyOn(service, 'setItem'); |
||||
|
service.setItem('test', 'value'); |
||||
|
expect(spy).toHaveBeenCalled(); |
||||
|
}); |
||||
|
|
||||
|
it('should be called removeItem', () => { |
||||
|
const spy = jest.spyOn(service, 'removeItem'); |
||||
|
service.removeItem('test'); |
||||
|
expect(spy).toHaveBeenCalled(); |
||||
|
}); |
||||
|
|
||||
|
it('should be called clear', () => { |
||||
|
const spy = jest.spyOn(service, 'clear'); |
||||
|
service.clear(); |
||||
|
expect(spy).toHaveBeenCalled(); |
||||
|
}); |
||||
|
|
||||
|
it('should be called key', () => { |
||||
|
const spy = jest.spyOn(service, 'key'); |
||||
|
service.key(0); |
||||
|
expect(spy).toHaveBeenCalled(); |
||||
|
}); |
||||
|
|
||||
|
it('should be called length', () => { |
||||
|
const spy = jest.spyOn(service, 'length', 'get'); |
||||
|
service.length; |
||||
|
expect(spy).toHaveBeenCalled(); |
||||
|
}); |
||||
|
}); |
||||
Loading…
Reference in new issue