13 changed files with 177 additions and 193 deletions
@ -0,0 +1,116 @@ |
|||||
|
|
||||
|
using IdentityModel; |
||||
|
using IdentityServer4.Events; |
||||
|
using IdentityServer4.Models; |
||||
|
using IdentityServer4.Services; |
||||
|
using IdentityServer4.Validation; |
||||
|
using LINGYUN.Abp.WeChat; |
||||
|
using LINGYUN.Abp.WeChat.OpenId; |
||||
|
using LINGYUN.Abp.WeChat.Security.Claims; |
||||
|
using Microsoft.AspNetCore.Identity; |
||||
|
using Microsoft.Extensions.Localization; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Extensions.Logging.Abstractions; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Security.Claims; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Identity; |
||||
|
using Volo.Abp.IdentityServer.Localization; |
||||
|
using Volo.Abp.Security.Claims; |
||||
|
using IdentityResource = Volo.Abp.Identity.Localization.IdentityResource; |
||||
|
using IdentityUser = Volo.Abp.Identity.IdentityUser; |
||||
|
|
||||
|
namespace LINGYUN.Abp.IdentityServer.WeChat |
||||
|
{ |
||||
|
public abstract class WeChatGrantValidator : IExtensionGrantValidator |
||||
|
{ |
||||
|
public abstract string GrantType { get; } |
||||
|
public abstract string LoginProviderKey { get; } |
||||
|
public abstract string AuthenticationMethod { get; } |
||||
|
|
||||
|
public ILogger Logger { protected get; set; } |
||||
|
protected IEventService EventService { get; } |
||||
|
protected IWeChatOpenIdFinder WeChatOpenIdFinder { get; } |
||||
|
protected IIdentityUserRepository UserRepository { get; } |
||||
|
protected UserManager<IdentityUser> UserManager { get; } |
||||
|
protected IStringLocalizer<IdentityResource> IdentityLocalizer { get; } |
||||
|
protected IStringLocalizer<AbpIdentityServerResource> IdentityServerLocalizer { get; } |
||||
|
|
||||
|
public WeChatGrantValidator( |
||||
|
IEventService eventService, |
||||
|
IWeChatOpenIdFinder weChatOpenIdFinder, |
||||
|
UserManager<IdentityUser> userManager, |
||||
|
IIdentityUserRepository userRepository, |
||||
|
IStringLocalizer<IdentityResource> identityLocalizer, |
||||
|
IStringLocalizer<AbpIdentityServerResource> identityServerLocalizer) |
||||
|
{ |
||||
|
EventService = eventService; |
||||
|
UserManager = userManager; |
||||
|
UserRepository = userRepository; |
||||
|
WeChatOpenIdFinder = weChatOpenIdFinder; |
||||
|
IdentityLocalizer = identityLocalizer; |
||||
|
IdentityServerLocalizer = identityServerLocalizer; |
||||
|
|
||||
|
Logger = NullLogger<WeChatGrantValidator>.Instance; |
||||
|
} |
||||
|
|
||||
|
protected abstract Task<WeChatOpenId> FindOpenIdAsync(string code); |
||||
|
|
||||
|
public async Task ValidateAsync(ExtensionGrantValidationContext context) |
||||
|
{ |
||||
|
var raw = context.Request.Raw; |
||||
|
var credential = raw.Get(OidcConstants.TokenRequest.GrantType); |
||||
|
if (credential == null || !credential.Equals(GrantType)) |
||||
|
{ |
||||
|
Logger.LogWarning("Invalid grant type: not allowed"); |
||||
|
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, IdentityServerLocalizer["InvalidGrant:GrantTypeInvalid"]); |
||||
|
return; |
||||
|
} |
||||
|
// TODO: 统一命名规范, 微信认证传递的 code 改为 WeChatOpenIdConsts.WeCahtCodeKey
|
||||
|
var wechatCode = raw.Get(AbpWeChatGlobalConsts.TokenName); |
||||
|
if (wechatCode.IsNullOrWhiteSpace() || wechatCode.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
Logger.LogWarning("Invalid grant type: wechat code not found"); |
||||
|
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, IdentityServerLocalizer["InvalidGrant:WeChatCodeNotFound"]); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var wechatOpenId = await FindOpenIdAsync(wechatCode); |
||||
|
var currentUser = await UserManager.FindByLoginAsync(LoginProviderKey, wechatOpenId.OpenId); |
||||
|
if (currentUser == null) |
||||
|
{ |
||||
|
Logger.LogWarning("Invalid grant type: wechat openid not register", wechatOpenId.OpenId); |
||||
|
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, IdentityServerLocalizer["InvalidGrant:WeChatNotRegister"]); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (await UserManager.IsLockedOutAsync(currentUser)) |
||||
|
{ |
||||
|
Logger.LogInformation("Authentication failed for username: {username}, reason: locked out", currentUser.UserName); |
||||
|
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, IdentityLocalizer["Volo.Abp.Identity:UserLockedOut"]); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var sub = await UserManager.GetUserIdAsync(currentUser); |
||||
|
|
||||
|
var additionalClaims = new List<Claim>(); |
||||
|
if (currentUser.TenantId.HasValue) |
||||
|
{ |
||||
|
additionalClaims.Add(new Claim(AbpClaimTypes.TenantId, currentUser.TenantId?.ToString())); |
||||
|
} |
||||
|
additionalClaims.Add(new Claim(AbpWeChatClaimTypes.OpenId, wechatOpenId.OpenId)); |
||||
|
if (!wechatOpenId.UnionId.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
additionalClaims.Add(new Claim(AbpWeChatClaimTypes.UnionId, wechatOpenId.UnionId)); |
||||
|
} |
||||
|
|
||||
|
await EventService.RaiseAsync(new UserLoginSuccessEvent(currentUser.UserName, wechatOpenId.OpenId, null)); |
||||
|
|
||||
|
context.Result = new GrantValidationResult(sub, AuthenticationMethod, additionalClaims.ToArray()); |
||||
|
|
||||
|
// 登录之后需要更新安全令牌
|
||||
|
(await UserManager.UpdateSecurityStampAsync(currentUser)).CheckErrors(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue