abp Vnext OpenIddect 扩展微信小程序授权登录

abp Vnext OpenIddect 扩展微信小程序授权登录_第1张图片

abp vnext6.0之后官方替换了原来的ids4,采用了openIddict的oauth认证框架。使用之前的方法已经不行,以下是OpenIddect 使用ITokenExtensionGrant接口进行的授权登入扩展,按照以下代码可实现,欢迎交流指正。

新建用于接收微信返回数据字段类

public class Results
{
  /// 
  /// 用户唯一标识
  /// 
  public string openid { get; set; }
  /// 
  /// 会话密钥
  /// 
  public string session_key { get; set; }
  /// 
  /// 用户在开放平台的唯一标识符,若当前小程序已绑定到微信开放平台帐号下会返回
  /// 
  public string unionid { get; set; }
  /// 
  /// 错误码
  /// 
  public int errcode { get; set; }
  /// 
  /// 错误信息
  /// 
  public string  errmsg { get; set; } 
}

在HttpApi.Host新建类

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using OpenIddict.Abstractions;
using OpenIddict.Server.AspNetCore;
using System.Collections.Generic;
using System.Net.Http;
using System.Security.Claims;
using System.Text.Json;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.OpenIddict.Controllers;
using Volo.Abp.OpenIddict.ExtensionGrantTypes;

namespace Demo
{
    [IgnoreAntiforgeryToken]
    [ApiExplorerSettings(IgnoreApi = true)]
    public class TokenExtensionGrant : AbpOpenIdDictControllerBase, ITokenExtensionGrant
    {
        protected IOptions<IdentityOptions> IdentityOptions => LazyServiceProvider.LazyGetRequiredService<IOptions<IdentityOptions>>();

        public const string ExtensionGrantName = "wechat_code";
        public string Name => ExtensionGrantName;

        public async Task<IActionResult> HandleAsync(ExtensionGrantContext context)
        {
            LazyServiceProvider = context.HttpContext.RequestServices.GetRequiredService<IAbpLazyServiceProvider>();

            string code = context.Request.GetParameter("code").ToString();
            if (string.IsNullOrEmpty(code))
            {
                return NewForbidResult("code参数为空!");
            }
            var results = GetResults(context, code);

            switch (results.errcode)
            {
                case 0:
                    string providerKey = results.openid;
                    var claimsPrincipal = await ServerValidate(context, "wechat", providerKey);
                    return claimsPrincipal == null ? 
                        RetForbidResult("未绑定微信") 
                        : 
                        SignIn(claimsPrincipal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
                //可以自行根据微信返回错误代码进行相应的错误处理
                default:
                    return NewForbidResult(results.errmsg);
            }
        }
        
        private ForbidResult NewForbidResult(string msg)
        {
            return new ForbidResult(
                new[] { OpenIddictServerAspNetCoreDefaults.AuthenticationScheme },
                GetAuthenticationProperties(msg));
        }

        private AuthenticationProperties GetAuthenticationProperties(string msg)
        {
            return new AuthenticationProperties(new Dictionary<string, string>
            {
                [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidRequest,
                [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = msg
            });
        }
        /// 
        /// 服务器验证
        /// 
        /// 
        /// 
        /// 
        /// 
        private async Task<ClaimsPrincipal> ServerValidate(ExtensionGrantContext context, string loginProvider, string providerKey)
        {
            await IdentityOptions.SetAsync();

            var user = await UserManager.FindByLoginAsync(loginProvider, providerKey);
            if (user == null)
            {
                return null;
            }

            var principal = await SignInManager.CreateUserPrincipalAsync(user);

            var scopes = context.Request.GetScopes();
            principal.SetScopes(scopes);
            var resources = await GetResourcesAsync(scopes);
            principal.SetResources(resources);

            await SetClaimsDestinationsAsync(principal);

            return principal;
        }
        /// 
        /// 根据code得到微信openid
        /// 
        /// 
        /// 
        /// 
        private Results GetResults(ExtensionGrantContext context, string code) 
        {
            string _appid = "WeChat_appId";
            string _secret = "WeChat_secret";

            string url = string.Format(
                        "https://api.weixin.qq.com/sns/jscode2session?appid={0}&secret={1}&js_code={2}&grant_type=authorization_code", 
                        _appid,
                        _secret,
                        code);
            HttpClient client = new HttpClient();
            HttpResponseMessage response = client.GetAsync(url).Result;
            if (response.IsSuccessStatusCode)
            {
                string resContent = response.Content.ReadAsStringAsync().Result;
                var results = JsonSerializer.Deserialize<Results>(resContent);
                return results;
            }
            else 
            {
                return new Results { errmsg = "微信接口请求失败" };
            }
        }
    }
}

在HttpApiHostModule.cs 文件中添加注册

使用上面定义的ExtensionGrantName扩展的这个openiddict的认证流程的名字

public override void PreConfigureServices(ServiceConfigurationContext context)
    {
        ///······
        PreConfigure<OpenIddictServerBuilder>(builder =>
        {
            builder.Configure(options =>
            {
                options.GrantTypes.Add(Demo.ExtensionGrantName);
            });
        });
    }

请求地址和参数

host:/connect/token
methon:POST
media type:aplication/x-www-form-urlencoded
body:
	grant_type=wechat_code
	code=微信小程序提供的code
	client_id=自己项目的client_id
	scope=自己项目 openid offline_access

钉钉可参考本文进行OpenIddect 扩展授权登录,欢迎交流指正,谢谢阅读。

参考文章(感谢以下文章和作者):
【Abp vnext 6.0手机号验证码登录】【作者:瓦力】

你可能感兴趣的:(ABP,VNEXT,微信小程序,.netcore,ABP,Vnext,OpenIddict)