前言: 现在大多数网站项目都支持微信登录,付款,以及支付宝登录付款,这种方式也是能够让用户很快速便捷的注册本网站的账号,进行登录,以及后续的操作。相信小伙伴们看完之后,会对怎么与微信或者支付宝服务器打交道有很深的理解,就当做是一个敲门砖吧。那么本篇主要针对微信的验证登录来打开通往微信服务器的大门,下一篇会主要讲解一下支付宝付款验证对接。

本篇为原创,转载请标出处:http://www.cnblogs.com/gudu1/p/8087130.html

下面我会使用大量的代码,代码中添加完整的注释来解释与微信服务器对接的详细步骤:

首先呢,需要有一个微信公众号,当然是收费的,不过呢,微信给我们开发人员提供的有微信公众测试号来进行开发测试,虽然提供功能不是很全,开发测试是够用了,还是很到位的

微信测试号地址:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login

扫码登陆后呢,就是下面这个样子了:

上面这个appID 和 appsecret 很重要,正常的公众号appsecret 一定不要暴露出去,不然是很危险的。

>> URL: 规则 http://服务器地址或者域名/项目验证接口路由,比如: http://www.mmm.cn/testProject/weChat.do,这个weChat.do 就是要跟微信服务器验证对接的接口

>> Token:这个是由用户自己来定义,主要是我们的项目跟微信服务器对接时候需要进行SHA1加密和解密的字段之一,详细请看官方文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319

>> 域名: 这里就需要使用你自己的域名了,当然域名是要指向能够被外网访问到的服务器地址。

当我们在接口配置信息这里点击提交,微信服务器就会向我们的服务器接口发送消息来进行验证是否正确。

当然还需要修改一处,这里需要的还是服务器域名:

接下来呢,就要看我们的程序跟微信验证的代码流程:

这里呢,我使用的 Spring 来做:

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.util.wechat.SignUtil;@Controller
@RequestMapping("wechat")
public class WechatController {private static Logger log = LoggerFactory.getLogger(WechatController.class);@RequestMapping(method = { RequestMethod.GET })public void doGet(HttpServletRequest request, HttpServletResponse response) {log.debug("weixin get...");// 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。String signature = request.getParameter("signature");// 时间戳String timestamp = request.getParameter("timestamp");// 随机数String nonce = request.getParameter("nonce");// 随机字符串String echostr = request.getParameter("echostr");// 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败PrintWriter out = null;try {out = response.getWriter();if (SignUtil.checkSignature(signature, timestamp, nonce)) {log.debug("weixin get success....");          // 我们验证通过,确定是微信发过来的消息,就将 随机字符串原样返回给微信out.print(echostr);}} catch (IOException e) {e.printStackTrace();} finally {if (out != null)out.close();}}
}

微信发过来的消息会到这里,可以看到我们的Controller的RequestMappiing 路由为 "wechat", 这就是我们在微信测试号中配置的接口路由地址,很明显,这是一个Servlet ,请求的是doGet 方法。

上面代码只是我们的入口,主要验证逻辑在下面:

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;/*** 微信请求校验工具类*/
public class SignUtil {// 与接口配置信息中的Token要一致private static String token = "mytoken";/*** 验证签名* * @param signature* @param timestamp* @param nonce* @return*/public static boolean checkSignature(String signature, String timestamp, String nonce) {String[] arr = new String[] { token, timestamp, nonce };// 将token、timestamp、nonce三个参数进行字典序排序
        Arrays.sort(arr);// 将三个字符串排序之后合并为一个StringBuilder content = new StringBuilder();for (int i = 0; i < arr.length; i++) {content.append(arr[i]);}MessageDigest md = null;String tmpStr = null;try {//  获得SHA-1 加密的对象md = MessageDigest.getInstance("SHA-1");// 将三个参数字符串拼接成一个字符串进行sha1加密byte[] digest = md.digest(content.toString().getBytes());// 将字节数组转换为十六进制字符串tmpStr = byteToStr(digest);} catch (NoSuchAlgorithmException e) {e.printStackTrace();}content = null;// 将sha1加密后的字符串可与signature对比,标识该请求来源于微信return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;}/*** 将字节数组转换为十六进制字符串* * @param byteArray* @return*/private static String byteToStr(byte[] byteArray) {String strDigest = "";for (int i = 0; i < byteArray.length; i++) {strDigest += byteToHexStr(byteArray[i]);}return strDigest;}/*** 将字节转换为十六进制字符串* * @param mByte* @return*/private static String byteToHexStr(byte mByte) {char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };char[] tempArr = new char[2];tempArr[0] = Digit[(mByte >>> 4) & 0X0F];tempArr[1] = Digit[mByte & 0X0F];String s = new String(tempArr);return s;}
}

细心看的小伙伴肯定已经注意到了, 在方法上面有一个字段就是token,这里一定要跟微信测试号中配置的保持 一致,不相信的同学可以测试着改一个不一致的,保证过不了。

这里的流程就是,微信首先 把我们的 token+时间戳+随机数 进行一次SHA-1 加密,然后发送给我们的程序,然后我们再进行一次SHA-1加密,然后跟微信发送过来的加密数据进行匹配。我们想象一下,有人故意破坏我们的程序,然后模拟发送数据,能吗?答案是能,不过他首先得拿到我们的token字段,才能使我们的程序给出正确响应,所以这里的token 配置一定要和微信测试号中配置保持一致。

好了,既然极影和微信服务器连通了,那么就开始我们的业务需求登录操作吧。

用户使用微信登录,肯定是需要向微信服务器发送登录请求,然后微信再回调我们的接口,接口获取微信服务器传递过来的信息,确定用户是否登录成功,包括用户的一些数据,比如:昵称,头像地址 等等。

业务流程:

第一步:请求CODE

  首先要知道这些接口是谁定义的,肯定是微信定义的了,那我们怎么知道向哪个接口发送消息,这就需要查看微信给我们提供的官方文档了。

  https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect , 该地址是程序向微信发送的第一条请求,请求参数中携带code

  下面来分析一下这条URL:

  appid:应用唯一标识,也就是微信测试号中的第一条 appid

  redirect_uri:使用urlEncode对链接进行处理,也就是微信服务器回调地址,地址就指向我们程序中处理用户是否登录的接口

  response_type: 就填写 code

   scope:应用授权作用域,拥有多个作用域用逗号(,)分隔,网页应用目前仅填写snsapi_login即可

   state:用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验

接下来就贴一下我的程序代码帮助理解:

import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;import com.util.wechat.WechatUtil;/*** 获取关注公众号之后的微信用户信息的接口,如果在微信浏览器里访问* https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxd7f6c5b8899fba83&redirect_uri=http://o2o.yitiaojieinfo.com/o2o/wechatlogin/logincheck&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect* 则这里将会获取到code,之后再可以通过code获取到access_token 进而获取到用户信息* @author xiangze**/
@Controller
@RequestMapping("wechatlogin")
public class WechatLoginController {private static Logger log = LoggerFactory.getLogger(WechatLoginController.class);private static final String FRONTEND = "1";private static final String SHOPEND = "2";@Autowiredprivate PersonInfoService personInfoService;@Autowiredprivate WechatAuthService wechatAuthService;@RequestMapping(value = "/logincheck", method = { RequestMethod.GET })public String doGet(HttpServletRequest request, HttpServletResponse response) {log.debug("weixin login get...");// 获取微信公众号传输过来的code,通过code可获取access_token,进而获取用户信息String code = request.getParameter("code");// 这个state可以用来传我们自定义的信息,方便程序调用,这里也可以不用String roleType = request.getParameter("state");log.debug("weixin login code:" + code);WechatUser user = null;String openId = null;WechatAuth auth = null;if (null != code) {UserAccessToken token;try {// 通过code获取access_tokentoken = WechatUtil.getUserAccessToken(code);log.debug("weixin login token:" + token.toString());// 通过token获取accessTokenString accessToken = token.getAccessToken();// 通过token获取openIdopenId = token.getOpenId();// 通过access_token和openId获取用户昵称等信息user = WechatUtil.getUserInfo(accessToken, openId);log.debug("weixin login user:" + user.toString());request.getSession().setAttribute("openId", openId);auth = wechatAuthService.getWechatAuthByOpenId(openId);} catch (IOException e) {log.error("error in getUserAccessToken or getUserInfo or findByOpenId: " + e.toString());e.printStackTrace();}}// 若微信帐号为空则需要注册微信帐号,同时注册用户信息if (auth == null) {PersonInfo personInfo = WechatUtil.getPersonInfoFromRequest(user);auth = new WechatAuth();auth.setOpenId(openId);if (FRONTEND.equals(roleType)) {personInfo.setUserType(1);} else {personInfo.setUserType(2);}auth.setPersonInfo(personInfo);WechatAuthExecution we = wechatAuthService.register(auth);if (we.getState() != WechatAuthStateEnum.SUCCESS.getState()) {return null;} else {personInfo = personInfoService.getPersonInfoById(auth.getPersonInfo().getUserId());request.getSession().setAttribute("user", personInfo);}} else {request.getSession().setAttribute("user", auth.getPersonInfo());}// 若用户点击的是前端展示系统按钮则进入前端展示系统if (FRONTEND.equals(roleType)) {return "frontend/index";} else {return "shop/shoplist";}}
}

第二步:通过code获取用户access_token

  调用接口:https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

  代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;/*** 微信工具类* * @author xiangze**/
public class WechatUtil {private static Logger log = LoggerFactory.getLogger(WechatUtil.class);/*** 获取UserAccessToken实体类* * @param code* @return* @throws IOException*/public static UserAccessToken getUserAccessToken(String code) throws IOException {// 测试号信息里的appIdString appId = "你的微信测试号appid";log.debug("appId:" + appId);// 测试号信息里的appsecretString appsecret = "你的微信测试号appsecret";log.debug("secret:" + appsecret);// 根据传入的code,拼接出访问微信定义好的接口的URLString url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appId + "&secret=" + appsecret+ "&code=" + code + "&grant_type=authorization_code";// 向相应URL发送请求获取token json字符串String tokenStr = httpsRequest(url, "GET", null);log.debug("userAccessToken:" + tokenStr);UserAccessToken token = new UserAccessToken();ObjectMapper objectMapper = new ObjectMapper();try {// 将json字符串转换成相应对象token = objectMapper.readValue(tokenStr, UserAccessToken.class);} catch (JsonParseException e) {log.error("获取用户accessToken失败: " + e.getMessage());e.printStackTrace();} catch (JsonMappingException e) {log.error("获取用户accessToken失败: " + e.getMessage());e.printStackTrace();} catch (IOException e) {log.error("获取用户accessToken失败: " + e.getMessage());e.printStackTrace();}if (token == null) {log.error("获取用户accessToken失败。");return null;}return token;}/*** 发起https请求并获取结果* * @param requestUrl*            请求地址* @param requestMethod*            请求方式(GET、POST)* @param outputStr*            提交的数据* @return json字符串*/public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {StringBuffer buffer = new StringBuffer();try {// 创建SSLContext对象,并使用我们指定的信任管理器初始化TrustManager[] tm = { new MyX509TrustManager() };SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");sslContext.init(null, tm, new java.security.SecureRandom());// 从上述SSLContext对象中得到SSLSocketFactory对象SSLSocketFactory ssf = sslContext.getSocketFactory();URL url = new URL(requestUrl);HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();httpUrlConn.setSSLSocketFactory(ssf);httpUrlConn.setDoOutput(true);httpUrlConn.setDoInput(true);httpUrlConn.setUseCaches(false);// 设置请求方式(GET/POST)
            httpUrlConn.setRequestMethod(requestMethod);if ("GET".equalsIgnoreCase(requestMethod))httpUrlConn.connect();// 当有数据需要提交时if (null != outputStr) {OutputStream outputStream = httpUrlConn.getOutputStream();// 注意编码格式,防止中文乱码outputStream.write(outputStr.getBytes("UTF-8"));outputStream.close();}// 将返回的输入流转换成字符串InputStream inputStream = httpUrlConn.getInputStream();InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");BufferedReader bufferedReader = new BufferedReader(inputStreamReader);String str = null;while ((str = bufferedReader.readLine()) != null) {buffer.append(str);}bufferedReader.close();inputStreamReader.close();// 释放资源
            inputStream.close();inputStream = null;httpUrlConn.disconnect();log.debug("https buffer:" + buffer.toString());} catch (ConnectException ce) {log.error("Weixin server connection timed out.");} catch (Exception e) {log.error("https request error:{}", e);}return buffer.toString();}
}

因为我们发送的是https请求,所以还需要有这么一个工具方法,发起 https 请求。。。

OK,以上就是微信验证以及登录的全过程,可能并不是很详细,不过理解这个过程应该是可以了,那么下篇会讲解一下支付宝付款的流程以及代码。

              The End。。。。。。

转载于:https://www.cnblogs.com/gudu1/p/8087130.html

微信验证以及登录流程相关推荐

  1. 微信小程序-微信小程序登录流程(一)

    微信小程序,小程序的一种,英文名Wechat Mini Program,是一种不需要下载安装即可使用的应用,它实现了应用"触手可及"的梦想,用户扫一扫或搜一下即可打开应用 冷启动: ...

  2. 微信小程序登录流程+介绍wx.login和auth.code2Session

    微信小程序登录流程+介绍wx.login和auth.code2Session 几个核心API和核心字段 wx.login() 调用接口获取登录凭证(code) code2Session 登录凭证校验, ...

  3. Python Flask微信小程序登录流程及登录api实现代码

    1.小程序端调用wx.login 2.判断用户是否授权 3.小程序端访问 wx.getUserInfo 4.小程序端js代码:+ wx.login({success: resp => {// 发 ...

  4. 微信小程序登录流程php,微信小程序登录流程​

    对于小程序的登录流程微信官方文档也有描述不清的情况,作为一个后端开发研究了小程序关于登录的所有信息对整个登录流程做一个梳理. 首先明确一点,这里指的小程序登录时wx.login(),并不是授权获取用户 ...

  5. QQ微信微博联合登录流程总结

    第三方联合登录一般可以降低网站的获客成本,所以一般的网站都会做一些联合登录,常用的就是QQ.微信.微博了,下面简单的介绍一下这些联合登录的方法. 看了一号店的QQ登录源码可知,点击图标直接访问的是这个 ...

  6. 网站使用微信扫码登录流程

    微信扫码登录是一个标准的oauth 2.0的过程. 1.用户请求访问网站,选择微信登录. 2.redirect到微信二维码页面 3.获取微信登录二维码,请求参数包括本网站的appId和登录成功后跳转回 ...

  7. Python-Flask微信小程序登录流程详解及后台实现

    文章目录 登录流程图及个人理解 登录接口源码 登录流程图及个人理解 1.前端将由wx.login()方法获取到的用户临时登录凭证code(只能使用一次)传给后台服务器(即登录接口) 2.后台利用微信小 ...

  8. 微信小程序登录流程,双登录,手机号登录和账户密码登录

    一.第一步: 在app.js文件中调用wx.login方法发送res.code和appid给后台,后台返回openid和session_key,把openid和session_key存入storage ...

  9. 跨平台跨端的登录流程及其安全设计

    跨平台跨端的登录流程及其安全设计 目录 跨平台跨端的登录流程及其安全设计 一.登录流程 1.1.登录流程时序图 1.2.三方App 登录 1.3.请求的路由守卫 二.注册流程 2.1.注册流程时序图 ...

最新文章

  1. python修改html的td_python3修改HTMLTestRunner,生成有截图的测试报告,并发送测试邮件(一)...
  2. PyTorch 官方教程发布,限时免费开放!
  3. ad09只在一定范围内查找相似对象_kafka日志段中的二分查找
  4. 数据结构猴子选大王java_数据结构例子-猴子选大王
  5. GNU __attribute__ 总结
  6. 100小时学习SAP之自学环境(一)
  7. 微信公众号文章采集浅谈--搜狗APP近一天文章
  8. 计算机上平方米的单位,word怎么写平方米 word中平方米的单位怎么打
  9. 00Cascading Style Sheet
  10. Linux的命令和快捷键
  11. 命令行实现URL编解码
  12. 软考干货 | 备考进行ing!该怎么备考呢?
  13. Android 使用高德SDK实现导航笔记,android热更新原理
  14. 【LOJ】apio2016烟火表演-可并堆凸包
  15. 百度云加速zblog和WordPress规则自定义
  16. python 文本词汇,句子校正 autocorrect库的使用
  17. (一)You Impress Me: Dialogue Generation via Mutual Persona Perception
  18. Vue实现二选一、菜单更多功能:
  19. 大三小生浅谈如何学C
  20. 【陈工笔记】# 人脸识别的实际操作记录 #

热门文章

  1. java工具类去掉字符串String中的.点。android开发java程序员常用工具类
  2. 分享 - Social.framework
  3. note-删除Visual Studio recent Projects list
  4. shell脚本[] [[]] -n -z 的含义解析
  5. sublime提示There are no packages available for installation解决办法
  6. 假几何真逆序数 NB HDU3465
  7. 第三章 用户界面设计
  8. text-overflow
  9. 使用ActivityGroup需要注意的地方
  10. url 自动加入链接