ABP Zero集成微信小程序登陆

时间:2018-05-10 13:22:29   收藏:0   阅读:2420

首先是ABPZero的第三方登陆模块,通过调用第三方的登录接口返回用户信息,再交给ABP的登陆验证模块去执行对应的登陆注册。

涉及的数据库表主要是技术分享图片这两个表,AbpUsers存储了用户信息,AbpUserLogins存储了登陆方式,第三方登陆的信息就是存储在这里的

技术分享图片

 

 主要是四个字段 LoginProvider ProviderKey TenantId UserId

        登陆提供器   用户唯一Id  对应的租户Id和用户Id

首先需要编写一个LoginProvider,代码如下

using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Abp.AspNetZeroCore.Web.Authentication.External;
using Castle.Core.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Schema;

namespace Web.Authentication.External
{
    public class WechatMiniProgramAuthProviderApi : ExternalAuthProviderApiBase
    {
        /// <summary>
        /// 微信小程序
        /// </summary>
        public const string ProviderName = "WeChatMiniProgram";
        WeChatMiniProgramOptions _options;
        JSchema schema = JSchema.Parse(JsonConvert.SerializeObject(new WeChatSession()));
        JSchema accessSchema = JSchema.Parse(JsonConvert.SerializeObject(new { AccessCode="", Name="" }));
        const string url = "https://api.weixin.qq.com/sns/jscode2session?appid={0}&secret={1}&grant_type=authorization_code&js_code={2}";
        private readonly IExternalAuthConfiguration _externalAuthConfiguration;
        private readonly ILogger logger;
        public WechatMiniProgramAuthProviderApi(IExternalAuthConfiguration externalAuthConfiguration, ILogger logger)
        {
            _externalAuthConfiguration = externalAuthConfiguration;
            var r = externalAuthConfiguration.Providers.First(p => p.Name == ProviderName);
            _options = new WeChatMiniProgramOptions
            {
                AppId = r.ClientId,
                Secret = r.ClientSecret
            };

            this.logger = logger;
        }

        public async override Task<ExternalAuthUserInfo> GetUserInfo(string accessCode)//因为需要获取微信放进User.Name 
        {                                              //所以accessCode需要多一个Name
            JObject jObject = JObject.Parse(accessCode);              //就长这样 {"AccessCode":"xxxxxxxx", "Name":"Sam"}
            if (!jObject.IsValid(accessSchema))                    //所以用Jobect解析出来
            {
                throw new Abp.UI.UserFriendlyException("accessCode Json inVaild");
            }
            accessCode = jObject["AccessCode"].ToString();
            string name = jObject["Name"].ToString();
            //string rowData = jObject["RowData"].ToString();
            var result = await GetOpenId(accessCode);                 //获取到OpenId,说明accessCode是对的   实际上应该再通过OpenId解密数据后获取NickName的,偷懒了...
            //logger.Info("OpenId:" + result.Openid);                 //获取不到则在方法内部抛出异常,不会返回用户信息,也就不会执行之后的登陆注册操作
            var t = result == null ? new ExternalAuthUserInfo() : new ExternalAuthUserInfo//
            {
                EmailAddress = result.Openid + "@test.cn",
                Surname = name,
                ProviderKey = result.Openid,//唯一
                Provider = ProviderName,
                Name = name
            };
            return t;
            
        }

        private async Task<WeChatSession>  GetOpenId(string code)
        {
            string geturl = string.Format(url, _options.AppId, _options.Secret, code);
            HttpClient client = new HttpClient();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            var result = await client.GetAsync(geturl);
            if (result.IsSuccessStatusCode)
            {                           //{"errcode":40163,"errmsg":"code been used, hints: [ req_id: tWZH6a0160th19 ]"}
                string re = await result.Content.ReadAsStringAsync();//{"session_key":"eafmjK9FYzCVpqPSo\/FBsQ==","openid":"oUigJ47QGkNOOXUjHkii5LyJbukw"}
                var jo = JObject.Parse(re);
                if (jo.IsValid(schema))
                {
                    var m = JsonConvert.DeserializeObject<WeChatSession>(re);
                    return m;
                }
            }
            return null ;
        }
    }

    class WeChatSession
    {
        public string Openid { get; set; }
        public string Session_key { get; set; }
    }

  /// <summary>
    /// 微信小程序配置选项
    /// </summary>
    public class WeChatMiniProgramOptions
    {
        /// <summary>
        /// AppId
        /// </summary>
        public string AppId { get; set; }
        /// <summary>
        /// 密钥
        /// </summary>
        public string Secret { get; set; }
    } }

然后在appsettings.json的Authentication节点中配置微信小程序的开启和appid 密钥的配置

技术分享图片

然后在WebHostModule.cs中判断是否开启,执行配置(如果是MVC项目则是 项目名+WebMVCModule.cs)

技术分享图片

因为默认的ProviderKey要求同一个登陆器下的同一用唯一,但是微信小程序里只有OpenId能做到用户唯一,OpenId又不能放到网络里传输,因此就需要修改一下默认的方式技术分享图片

注释掉 WebCore项目中Controller中TokenAuthController的GetExternalUserInfo方法中的判断调用接口传入ProviderKey和提供器返回用户信息ProviderKey一致。

这样Login表中的ProviderKey就会存储第一次登录时传入的accessCode。

 最后只需要调用ExternalAuthenticate接口就可以了

技术分享图片

 

需要注意的是这几个参数需要全部传入,哪怕传入为空。providerKey和ProviderAccessCode都传入微信小程序提供的accessCode。

技术分享图片

这样就会返回accessToken了,调用接口时Hearder加上Bearer  accessToken就可以了

 

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!