微信扫码登录实现
微信登录验证基于OAuth2.0
流程如下:
- 先申请公众号 ,然后在公众号里面配置应用的return域名
- 让用户通过扫码授权绑定微信号(绑定的时候就是将该用户的unioid和自己系统中的用户做一个对应关系,将unionid存下来)
具体程序流程:
A.通过初始url到微信获取登录二维码(如果是手机端则会直接弹出是否授权)url包含你的appid 和 redirect_uri(接收微信返回信息的API地址)例子:https://open.weixin.qq.com/connect/qrconnect?appid=wxXXXXXXXXXXX&redirect_uri=https%3A%2F%2Fpassport.XYZ.cn%2Fpassport2%2Flogin%3Fappid%3DCxaOne%26scope%3Duserinfo%26returnurl%3Dhttp%253A%252F%252Fdemo3.XYZ.cn%252Fauth%253Fr%253Dhttps%25253A%25252F%25252Fdemo3.XYZ.cn%25252Fme&response_type=code&scope=snsapi_login&state=XXXXa5
注意:
redirect_uri 里面是你微信公众号中配置的网站url才行
而且网站目录里面要放一个用于验证的txt文件
而且网站目录里面要放一个用于验证的txt文件
B.用户扫码登录/点击授权后,微信会返回一个appid+code回来到接收微信返回信息的API地址
C.API获取到code之后,通过appid+secret+code到微信获取该微信用户的信息,其中信息包括unionid(微信用户唯一id),还会返回一个openid 这个id是你这个应用内部针对这个微信用户的唯一id
D.如果正常返回unionid则表示用户登录成功,如果返回了errmsg,则失败
代码:
WechatLogin
[Route("wechatlogin")] [HttpGet] [ResponseType(typeof(EmployeeSession))] public IHttpActionResult WechatLogin() { var allUrlKeyValues = ControllerContext.Request.GetQueryNameValuePairs(); string appid = allUrlKeyValues.LastOrDefault(x => x.Key == "appid").Value; string state = allUrlKeyValues.LastOrDefault(x => x.Key == "state").Value; string code = allUrlKeyValues.LastOrDefault(x => x.Key == "code").Value; //根据不同的appid,获取不同的key,因pc端和手机端的appid不同 var oauth_app_key = ConfigurationManager.AppSettings[appid]; string send_url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appid + "&secret=" + oauth_app_key + "&code=" + code + "&grant_type=authorization_code"; //发送并接受返回值 string result = HttpGet(send_url); if (result.Contains("errmsg")) { throw new Exception(result);//登录失败 } try { //取到对应的unionid等信息 Dictionary<string, object> ssoUserInfo = JsonConvert.DeserializeObject<Dictionary<string, object>>(result); //初始化时使用模板数据库 var initialContext = new ApolloAppContextImp(ConfigurationManager.AppSettings["CLIENT_DB_TEMPLATE_NAME"]); using (var serviceContext = new ServiceContext(initialContext)) { var loginDataWeChat = serviceContext.AuthenticationService.GetCurrentLoginDataWeChat(ssoUserInfo); if (null != loginDataWeChat) {//已绑定,使用真实公司名称进入登录流程,并返回EmployeeSession initialContext = new ApolloAppContextImp(loginDataWeChat.ClientId); using (var serviceContextClient = new ServiceContext(initialContext)) { var employeeSession = serviceContextClient.AuthenticationService.WechatLogin(ssoUserInfo, loginDataWeChat); return Ok(employeeSession); } } else //未绑定,弹出公司ID,用户名,密码页面,让用户进行绑定 //用户输入后,mapping表添加数据 { HttpContext.Current.Session["ssoUserInfo"] = ssoUserInfo;//暂存到session,往loginDataWeChat添加纪录的时候需要 var employeeSession = new EmployeeSession(); employeeSession.HasBeenBindWechat = false; return Ok(employeeSession); } } } catch (Exception ex) { throw new Exception(ex.Message); } }
WechatLoginbind
[Route("wechatloginbind")] [HttpPost] [ResponseType(typeof(EmployeeSession))] public IHttpActionResult WechatLoginbind(UserCredentials userCredentials) { var initialContext = new ApolloAppContextImp(userCredentials.ClientName); //This is all we know at the moment. If the client id is wrong, it will be handled in the exception. try { using (var serviceContext = new ServiceContext(initialContext)) { EmployeeSession employeeSession; Dictionary<string, object> ssoUserInfo = HttpContext.Current.Session["ssoUserInfo"] as Dictionary<string, object>; if (serviceContext.AuthenticationService.UserLoginCheckAndBind(userCredentials, ssoUserInfo, out employeeSession)) { return Ok(employeeSession); } else { throw new ApiException(ExceptionLevel.Normal, ExceptionCode.UnAuthorized, "You have provided the wrong credentials.Please check your entries again."); } } } catch (ClientNotFoundException) { var appContext = new ApolloAppContextImp(userCredentials.ClientName); using (var serviceContext = new ServiceContext(appContext)) { throw new ApiException(ExceptionLevel.Critical, ExceptionCode.NotFound, serviceContext.GlobalizationService.GetLocalizationMessage(MessageDictionary.CLIENT_NOT_FOUND, CXA.Common.Enums.Globalization.LanguageEnum.enus, userCredentials.ClientName)); } } } public static string HttpGet(string url) { using (HttpClient client = new HttpClient()) { var result = client.GetAsync(url).Result; if (result.IsSuccessStatusCode == true) { return result.Content.ReadAsStringAsync().Result; } else { return "errmsg:" + result.Content.ReadAsStringAsync().Result; } } }
需要注意的就是pc端和手机端对微信来说属于不同的应用
好的程序员,他们删掉的代码,比留下来的还要多很多。