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 Microsoft.Extensions.Options; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Packages.Core; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Select2; |
|||
|
|||
[DependsOn(typeof(CoreScriptContributor))] |
|||
public class Select2ScriptContributor : BundleContributor |
|||
{ |
|||
public const string PackageName = "select2"; |
|||
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"); |
|||
} |
|||
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