Skip to content

Commit

Permalink
重构安全身份转换相关的设计和实现。 🍤
Browse files Browse the repository at this point in the history
  • Loading branch information
PopeyeZhong committed Mar 13, 2024
1 parent 5baa843 commit 3339b01
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 35 deletions.
89 changes: 89 additions & 0 deletions Zongsoft.Core/src/Security/ClaimsIdentityModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* _____ ______
* /_ / ____ ____ ____ _________ / __/ /_
* / / / __ \/ __ \/ __ \/ ___/ __ \/ /_/ __/
* / /__/ /_/ / / / / /_/ /\_ \/ /_/ / __/ /_
* /____/\____/_/ /_/\__ /____/\____/_/ \__/
* /____/
*
* Authors:
* 钟峰(Popeye Zhong) <[email protected]>
*
* Copyright (C) 2010-2020 Zongsoft Studio <http://www.zongsoft.com>
*
* This file is part of Zongsoft.Core library.
*
* The Zongsoft.Core is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3.0 of the License,
* or (at your option) any later version.
*
* The Zongsoft.Core is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the Zongsoft.Core library. If not, see <http://www.gnu.org/licenses/>.
*/

using System;
using System.Linq;
using System.Security.Claims;

namespace Zongsoft.Security
{
public static class ClaimsIdentityModel
{
#region 私有变量
private static readonly Caching.MemoryCache _cache = new();
#endregion

#region 公共方法
public static TIdentityModel Get<TIdentityModel>(string scheme = null) where TIdentityModel : class =>
GetCore<TIdentityModel>((Services.ApplicationContext.Current?.Principal ?? ClaimsPrincipal.Current) as CredentialPrincipal, scheme);

public static TIdentityModel Get<TIdentityModel>(string scheme, Func<TIdentityModel, Claim, bool> configure) where TIdentityModel : class =>
GetCore((Services.ApplicationContext.Current?.Principal ?? ClaimsPrincipal.Current) as CredentialPrincipal, scheme, identity => identity.AsModel(configure));

public static TIdentityModel Get<TIdentityModel>(string scheme, IClaimsIdentityTransformer transformer) where TIdentityModel : class =>
GetCore((Services.ApplicationContext.Current?.Principal ?? ClaimsPrincipal.Current) as CredentialPrincipal, scheme, identity => transformer.Transform(identity) as TIdentityModel);

public static TIdentityModel Get<TIdentityModel>(CredentialPrincipal principal, string scheme = null) where TIdentityModel : class =>
GetCore<TIdentityModel>(principal, scheme);

public static TIdentityModel Get<TIdentityModel>(CredentialPrincipal principal, string scheme, Func<TIdentityModel, Claim, bool> configure) where TIdentityModel : class =>
GetCore(principal, scheme, identity => identity.AsModel(configure));

public static TIdentityModel Get<TIdentityModel>(CredentialPrincipal principal, string scheme, IClaimsIdentityTransformer transformer) where TIdentityModel : class =>
GetCore(principal, scheme, identity => transformer.Transform(identity) as TIdentityModel);

private static TIdentityModel GetCore<TIdentityModel>(CredentialPrincipal principal, string scheme, Func<ClaimsIdentity, TIdentityModel> transform = null) where TIdentityModel : class
{
if(principal == null || principal.CredentialId == null)
return null;

//如果指定的安全主体中对应的身份模型已缓存则直接返回
if(_cache.TryGetValue(GetCacheKey(principal.CredentialId, scheme), out var identityModel) && identityModel != null)
return (TIdentityModel)identityModel;

//确认当前的安全身份标识
var identity = principal.GetIdentity(scheme);

//将当前安全身份标识转换为身份模型
var model = transform == null ? identity.AsModel<TIdentityModel>() : transform(identity);

//如果安全主体的有效期大于零则将身份模型缓存起来
if(principal.Validity > TimeSpan.Zero)
_cache.SetValue(GetCacheKey(principal.CredentialId, scheme), model, principal.Validity.TotalHours > 24 ? TimeSpan.FromHours(24) : principal.Validity);

return model;
}
#endregion

#region 私有方法
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
static string GetCacheKey(string credentialId, string scheme) => string.IsNullOrEmpty(scheme) ? credentialId : $"{credentialId}:{scheme}";
#endregion
}
}
5 changes: 1 addition & 4 deletions Zongsoft.Core/src/Security/ClaimsPrincipalTransformer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@
using System.Security.Claims;
using System.Security.Principal;

using Zongsoft.Security;
using Zongsoft.Security.Membership;

namespace Zongsoft.Security
{
[DefaultMember(nameof(Transformers))]
Expand Down Expand Up @@ -113,7 +110,7 @@ protected virtual object OnTransform(ClaimsIdentity identity)
return transformer.Transform(identity);
}

return identity.AsModel<IUserModel>();
return null;
}
#endregion
}
Expand Down
31 changes: 0 additions & 31 deletions Zongsoft.Core/src/Security/Membership/UserIdentityBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,6 @@ namespace Zongsoft.Security.Membership
{
public abstract class UserIdentityBase : IUserIdentity, IEquatable<IUserIdentity>
{
#region 静态变量
private static readonly Caching.MemoryCache _cache = new();
#endregion

#region 构造函数
protected UserIdentityBase() { }
#endregion
Expand All @@ -50,33 +46,6 @@ protected UserIdentityBase() { }
public string Description { get; set; }
#endregion

#region 静态方法
protected static TIdentity Get<TIdentity>(Func<ClaimsIdentity, TIdentity> transform) where TIdentity : class, IUserIdentity => Get((Services.ApplicationContext.Current?.Principal ?? ClaimsPrincipal.Current) as CredentialPrincipal, string.Empty, transform);
protected static TIdentity Get<TIdentity>(string scheme, Func<ClaimsIdentity, TIdentity> transform) where TIdentity : class, IUserIdentity => Get((Services.ApplicationContext.Current?.Principal ?? ClaimsPrincipal.Current) as CredentialPrincipal, scheme, transform);
protected static TIdentity Get<TIdentity>(CredentialPrincipal principal, Func<ClaimsIdentity, TIdentity> transform) where TIdentity : class, IUserIdentity => Get(principal, string.Empty, transform);
protected static TIdentity Get<TIdentity>(CredentialPrincipal principal, string scheme, Func<ClaimsIdentity, TIdentity> transform) where TIdentity : class, IUserIdentity
{
if(principal == null || principal.CredentialId == null)
return null;

//如果指定的安全主体对应的用户身份已缓存则直接返回
if(_cache.TryGetValue(principal.CredentialId, out var cachedUser) && cachedUser != null)
return (TIdentity)cachedUser;

//确认当前的安全身份标识
var identity = principal.GetIdentity(scheme);

//将当前安全身份标识转换为用户身份
var user = transform(identity);

//如果安全主体的有效期大于零则将用户身份缓存起来
if(principal.Validity > TimeSpan.Zero)
_cache.SetValue(principal.CredentialId, user, principal.Validity.TotalHours > 24 ? TimeSpan.FromHours(24) : principal.Validity);

return user;
}
#endregion

#region 重写方法
public bool Equals(IUserIdentity user) => user != null && user.UserId == this.UserId;
public override bool Equals(object obj) => this.Equals(obj as IUserIdentity);
Expand Down

0 comments on commit 3339b01

Please sign in to comment.