微信开发获取用户端ip_微信端获取用户ip - CSDN
精华内容
参与话题
  • 在做微信一键上网的功能,原本是用php来做,天知道原来苹果和安卓版的微信浏览器获取到的IP地址还是不一样的,苹果版的IP地址是真实的,安卓版的地址居然是代理地址(为何小龙要这处理?谁知道?),天知道用尽php所有...

    在做微信一键上网的功能,原本是用php来做,天知道原来苹果和安卓版的微信浏览器获取到的IP地址还是不一样的,苹果版的IP地址是真实的,安卓版的地址居然是代理地址(为何小龙要这处理?谁知道?),天知道用尽php所有方法都获取不到真实的客户端IP。于是开始转向java,果然不枉我爱它这么多年。

    一般获取客户端的IP地址的方法是:request.getRemoteAddr();但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实IP地址了。

    原因:由于在客户端和服务之间增加了中间代理,因此服务器无法直接拿到客户端的IP,服务器端应用也无法直接通过转发请求的地址返回给客户端。

    现在图示代理上网和IP的关系:

     

    第一种情况:不通过代理上网,服务器端拿到真实IP

     

    第二种情况:通过代理服务器如:Nginx,Squid等一层代理或多层代理上网,如下图:

     

    需要注意的是X-Forwarded-For和X-Real-IP都不是http的正式协议头,而是squid等反向代理软件最早引入的,之所以resin能拿到,是因为NGINX里一般缺省都会这么配置转发的http请求:

    location / {

             proxy_pass       http://yourdomain.com;

             proxy_set_header   Host             $host;

             proxy_set_header   X-Real-IP        $remote_addr;

             proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;

             },从X-Forwarded-For的定义来看,ips[0]才是原始客户端ip,如果这个都不是,那拿第二个就更不靠谱了,我们平时检验的时候,可能是直接在内网挂代理去访问的,跟外面网友访问经过的网络路径不一样,后面不停添加的是经过的每一层代理ip才对,下面举例说明;

    request.getRemoteAddr() 192.168.239.196

    request.getHeader("X-Forwarded-For") 58.63.227.162, 192.168.237.178, 192.168.238.218

    request.getHeader("X-Real-IP") 192.168.238.218

    所以访问的流程应该是这样,客户端58.63.227.162发出请求,经过192.168.237.178, 192.168.238.218两层转发,到了192.168.239.196这台NGINX上,NGINX就把X-Real-IP头设成了自己看到的remote_addr,也就是直接发给到他的192.168.238.218,这时候resin收到这个包,对resin来说直接发给他的remote_addr就是NGINX的ip,也就是192.168.239.196,那么resin里面的request.getRemoteAddr()就是192.168.239.196,那么在resin里拿最原始的ip逻辑(也就是拿能够知道的最外层的ip)应该是这样:

                如果XFF不为空,拿XFF的左边第一个

                如果XFF为空,拿XRI

                如果XRI为空,只能拿request.getRemoteAddr(),也就是只能拿到最直接发给他的机器ip了,

    其他都不可考究,参考代码如下:

    第一种代码:

    复制代码
          /**
          * 从Request对象中获得客户端IP,处理了HTTP代理服务器和Nginx的反向代理截取了ip
          * @param request
          * @return ip
          */
        public static String getLocalIp(HttpServletRequest request) {
            String remoteAddr = request.getRemoteAddr();
            String forwarded = request.getHeader("X-Forwarded-For");
            String realIp = request.getHeader("X-Real-IP");
    
            String ip = null;
            if (realIp == null) {
                if (forwarded == null) {
                    ip = remoteAddr;
                } else {
                    ip = remoteAddr + "/" + forwarded.split(",")[0];
                }
            } else {
                if (realIp.equals(forwarded)) {
                    ip = realIp;
                } else {
                    if(forwarded != null){
                        forwarded = forwarded.split(",")[0];
                    }
                    ip = realIp + "/" + forwarded;
                }
            }
            return ip;
        }
    复制代码

    第二种代码:

    复制代码
     1      public static String getIp(HttpServletRequest request) {
     2         String remoteAddr = request.getRemoteAddr();
     3         String forwarded = request.getHeader("X-Forwarded-For");
     4         String realIp = request.getHeader("X-Real-IP");
     5 
     6         String ip = null;
     7         if (realIp == null) {
     8             if (forwarded == null) {
     9                 ip = remoteAddr;
    10             } else {
    11                 ip = remoteAddr + "/" + forwarded;
    12             }
    13         } else {
    14             if (realIp.equals(forwarded)) {
    15                 ip = realIp;
    16             } else {
    17                 ip = realIp + "/" + forwarded.replaceAll(", " + realIp, "");
    18             }
    19         }
    20         return ip;
    21     }
    复制代码

    第三种代码:

    复制代码
     1        public static String getIp2(HttpServletRequest request) {
     2            String ip = request.getHeader("X-Forwarded-For");
     3            if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){
     4                //多次反向代理后会有多个ip值,第一个ip才是真实ip
     5                int index = ip.indexOf(",");
     6                if(index != -1){
     7                    return ip.substring(0,index);
     8                }else{
     9                    return ip;
    10                }
    11            }
    12            ip = request.getHeader("X-Real-IP");
    13            if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){
    14                return ip;
    15            }
    16            return request.getRemoteAddr();
    17        }
    复制代码

    第三种是最合适的,最清晰理解的(我选第三种)

    展开全文
  • 如果用户在微信客户端中访问第三方网页,公众号可以通过微信网页授权机制,来获取用户基本信息,进而实现业务逻辑。 现在,我们要实现一个微信内网页,通过微信访问网页时,网页会展示微信用户的个人信息。因为涉及...

    说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家!

    一丶概述

    • 微信网页授权

    如果用户在微信客户端中访问第三方网页,公众号可以通过微信网页授权机制,来获取用户基本信息,进而实现业务逻辑。

    现在,我们要实现一个微信内网页,通过微信访问网页时,网页会展示微信用户的个人信息。因为涉及到用户的个人信息,所以需要有用户授权才可以。当用户授权后,我们的网页服务器(开发者服务器)会拿到用户的“授权书”(code),我们用这个code向微信服务器领取访问令牌(accecc_token)和用户的身份号码(openid),然后凭借access_token和openid向微信服务器提取用户的个人信息。

    1. 第一步:用户同意授权,获取code
    2. 第二步:通过code换取网页授权access_token
    3. 第三步:拉取用户信息(需scope为 snsapi_userinfo)

    那么,如何拿到用户的授权code呢?

    授权是由微信发起让用户进行确认,在这个过程中是微信在与用户进行交互,所以用户应该先访问微信的内容,用户确认后再由微信将用户导向到我们的网页链接地址,并携带上code参数。我们把这个过程叫做网页回调,类似于我们在程序编写时用到的回调函数,都是回调的思想。

    • 关于网页授权回调域名的说明 

    1、在微信公众号请求用户网页授权之前,开发者需要先到公众平台官网中的“开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项中,修改授权回调域名。请注意,这里填写的是域名(是一个字符串),而不是URL,因此请勿加 http:// 等协议头;关于网页授权回调域名的说明

    2、授权回调域名配置规范为全域名,比如需要网页授权的域名为:www.qq.com,配置以后此域名下面的页面http://www.qq.com/music.html 、 http://www.qq.com/login.html 都可以进行OAuth2.0鉴权。但http://pay.qq.com 、 http://music.qq.com 、 http://qq.com无法进行OAuth2.0鉴权

    3、如果公众号登录授权给了第三方开发者来进行管理,则不必做任何设置,由第三方代替公众号实现网页授权即可。

    第一步:用户同意授权,获取code

    在确保微信公众账号拥有授权作用域(scope参数)的权限的前提下(服务号获得高级接口后,默认拥有scope参数中的snsapi_base和snsapi_userinfo),引导关注者打开如下页面:

    https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

    尤其注意:由于授权操作安全等级较高,所以在发起授权请求时,微信会对授权链接做正则强匹配校验,如果链接的参数顺序不对,授权页面将无法正常访问

    参考链接(请在微信客户端中打开此链接体验):
    scope为snsapi_base
    https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx520c15f417810387&redirect_uri=https%3A%2F%2Fchong.qq.com%2Fphp%2Findex.php%3Fd%3D%26c%3DwxAdapter%26m%3DmobileDeal%26showwxpaytitle%3D1%26vb2ctag%3D4_2030_5_1194_60&response_type=code&scope=snsapi_base&state=123#wechat_redirect
    scope为snsapi_userinfo
    https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxf0e81c3bee622d60&redirect_uri=http%3A%2F%2Fnba.bluewebgame.com%2Foauth_response.php&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirec

    尤其注意:跳转回调redirect_uri,应当使用https链接来确保授权code的安全性。

    参数说明

    参数 是否必须 说明
    appid 公众号的唯一标识
    redirect_uri 授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理
    response_type 返回类型,请填写code
    scope 应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息 )
    state 重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节
    #wechat_redirect 无论直接打开还是做页面302重定向时候,必须带此参数

     下图为scope等于snsapi_userinfo时的授权页面:

    用户同意授权后

    如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE。

    code说明 : code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。 

    第二步:通过code换取网页授权access_token

    首先请注意,这里通过code换取的是一个特殊的网页授权access_token,与基础支持中的access_token(该access_token用于调用其他接口)不同。公众号可通过下述接口来获取网页授权access_token。如果网页授权的作用域为snsapi_base,则本步骤中获取到网页授权access_token的同时,也获取到了openid,snsapi_base式的网页授权流程即到此为止。

    尤其注意:由于公众号的secret和获取到的access_token安全级别都非常高,必须只保存在服务器,不允许传给客户端。后续刷新access_token、通过access_token获取用户信息等步骤,也必须从服务器发起。

    请求方法

    获取code后,请求以下链接获取access_token:  https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

    参数说明

    参数 是否必须 说明
    appid 公众号的唯一标识
    secret 公众号的appsecret
    code 填写第一步获取的code参数
    grant_type 填写为authorization_code

    返回说明

    正确时返回的JSON数据包如下:

    { "access_token":"ACCESS_TOKEN",
    "expires_in":7200,
    "refresh_token":"REFRESH_TOKEN",
    "openid":"OPENID",
    "scope":"SCOPE" }
    参数 描述
    access_token 网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同
    expires_in access_token接口调用凭证超时时间,单位(秒)
    refresh_token 用户刷新access_token
    openid 用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenID
    scope 用户授权的作用域,使用逗号(,)分隔

     

    错误时微信会返回JSON数据包如下(示例为Code无效错误):

    {"errcode":40029,"errmsg":"invalid code"}

     第三步:拉取用户信息(需scope为 snsapi_userinfo)

    如果网页授权作用域为snsapi_userinfo,则此时开发者可以通过access_token和openid拉取用户信息了。

    请求方法

    http:GET(请使用https协议) https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN

    参数说明

    参数 描述
    access_token 网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同
    openid 用户的唯一标识
    lang 返回国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语

    返回说明

    正确时返回的JSON数据包如下:

    {    "openid":" OPENID",
    " nickname": NICKNAME,
    "sex":"1",
    "province":"PROVINCE"
    "city":"CITY",
    "country":"COUNTRY",
    "headimgurl":    "http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
    "privilege":[ "PRIVILEGE1" "PRIVILEGE2"     ],
    "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
    }
    参数 描述
    openid 用户的唯一标识
    nickname 用户昵称
    sex 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
    province 用户个人资料填写的省份
    city 普通用户个人资料填写的城市
    country 国家,如中国为CN
    headimgurl 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效。
    privilege 用户特权信息,json 数组,如微信沃卡用户为(chinaunicom)
    unionid 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。

    错误时微信会返回JSON数据包如下(示例为openid无效):

    {"errcode":40003,"errmsg":" invalid openid "}

     二丶代码实现

    • 思路分析
    • 首选在我们的flask程序中需要定义一个视图函数路由规则为/wechat8007/index,定义微信服务器重定向网址redirect_uri为服务器域名+/wechat8007/index(例如http://www.xxxx.com/wechat8007/index),通过访问微信提供的引导页面,让用户同意授权,然后重定向到我们定义的网址,此时微信服务器就会给我们的服务一个code,我们的服务器再通过code向微信服务器换取网页授权access_token(存取令牌),如果网页授权作用域为snsapi_userinfo,则此时可以通过access_token和openid拉取用户信息了。
    • step1 同意授权,这一块不需要代码实现,只需要提供授权链接即可
    • step2 定义视图函数,当用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE ,在flask程序中定义一个是视图函数接口index,让用户同意授权后,去访问的视图
    • 上一篇博客定义的wechat视图,是由微信服务器访问,现在定义的index视图为用户访问的
    @app.route("/wechat8007/index")
    def index():
        """让用户通过微信访问的网页页面视图"""
    • step3  刚开始还没拉去用户资料时,可直接返回一个模板
    return render_template("index.html")
    • step4 从微信服务器中获取用户的资料数据,将用户的资料数据填充到index.html模板中
    • 1.获取code参数
    code = request.args.get("code")
    • 2.当code不存在时,返回字符串
    if not code:
        return u"缺失code参数"
    url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code" %(WECHAT_APPID,WECHAT_APPSECRET,code)
    
    response = urllib2.urlopen(url)
    
    # 获取响应体数据,微信返回的json数据
    json_str = response.read()
    resp_dict = json.loads(json_str)
    • 4.提取access_token,首先对获取到的响应体数据进行判断,如果不存在,直接返回提示字符串,存在则通过get方式拿去字典中的access_token键的值以及用户编号openid的值
    if "errcode" in resp_dict:
        return u"获取access_token失败"
    
    access_token = resp_dict.get("access_token")
    open_id = resp_dict.get("openid")  # 用户的编号
    • step5 向微信服务器发送http请求,获取用户的资料数据 
    url = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN" %(access_token,open_id)
    
    response = urllib2.urlopen(url)
    
    # 读取微信传回的json的响应体数据
    user_json_str = response.read()
    user_dict_data = json.loads(user_json_str)
    • step6 判断微信返回的响应体数据中是否有errorcode字段,如果存在则返回失败信息,不存在说明微信返回的json数据为正确数据,则将该数据传给index.html模板,当用户访问 http://xxx/wechat8007/index地址时,会渲染出我们定义的index.html模板
    if "errcode" in user_dict_data:
        return u"获取用户信息失败"
    else:
        # 将用户的资料数据填充到页面中
        return render_template("index.html", user=user_dict_data)
    •  step7 当前目录下创建templates模板目录,在该目录中创建index.html文件 ,代码如下
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>{{user["nickname"]}}的个人主页</title>
    </head>
    <body>
        <img alt="头像" src="{{user['headimgurl']}}" width="60">
        <table>
            <tr>
                <th>openid</th>
                <td>{{user["openid"]}}</td>
            </tr>
            <tr>
                <th>昵称</th>
                <td>{{user["nickname"]}}</td>
            </tr>
            <tr>
                <th>性别</th>
                <td>
                    {% if 1 == user["sex"] %}
                        男
                    {% elif 2 == user["sex"] %}
                        女
                    {% else %}
                        未知
                    {% endif %}
                </td>
            </tr>
            <tr>
                <th>省份</th>
                <td>{{user["province"]}}</td>
            </tr>
            <tr>
                <th>城市</th>
                <td>{{user["city"]}}</td>
            </tr>
            <tr>
                <th>国家</th>
                <td>{{user["country"]}}</td>
            </tr>
        </table>
    </body>
    </html>

     三丶部署测试

    • step1 将代码推送到服务器上

    成功推送到服务器上

    •  step2 在服务器上进入虚拟环境,运行此程序

     

    In [1]: import urllib
    
    In [2]: urllib.quote("http://www.xxx.com/wechat8007/index")
    Out[2]: 'http%3A//www.xxx.com/wechat8007/index'
    
    
    

     

    • 拼接好的用户访问的url地址为

    • step4 可以将该网址生成二维码,使用微信扫一扫,也可以在接口公众号直接发送此链接地址
    •  使用谷歌浏览器的二维码插件,将网址生成对应的二维码(这里以百度首页网址为例)

    • 直接在浏览器中输入此地址会提示请在微信客户端打开链接

    •  step5 测试,在手机微信上打开此链接,出现授权登录提示,点击允许即可获取用户个人信息

    点击允许后,进入如下界面

    点击继续访问,则出现博主个人的微信信息了,如下图 

    此时查看服务器上程序运行日志 

    四丶完整代码

    # coding:utf-8
    from flask import Flask, request, render_template
    import json, urllib2
    
    
    WECHAT_APPID = "yourappid"
    WECHAT_APPSECRET = "yoursecret"
    
    app = Flask(__name__)
    
    
    
    @app.route("/wechat8007/index")
    def index():
    
        code = request.args.get("code")
    
        if not code:
            return u"缺失code参数"
    
        url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code" % (WECHAT_APPID, WECHAT_APPSECRET, code)
    
        response = urllib2.urlopen(url)
    
        json_str = response.read()
        resp_dict = json.loads(json_str)
    
        if "errcode" in resp_dict:
            return u"获取access_token失败"
    
        access_token = resp_dict.get("access_token")
        open_id = resp_dict.get("openid")
    
        url = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN" % (access_token, open_id)
    
        response = urllib2.urlopen(url)
        user_json_str = response.read()
        user_dict_data = json.loads(user_json_str)
    
        if "errcode" in user_dict_data:
            return u"获取用户信息失败"
        else:
            return render_template("index.html", user=user_dict_data)
    
    
    if __name__ == '__main__':
        app.run(port=8007, debug=True)

    总结:微信公众号接口开发,根据官方提供的开发文档,进行开发,逻辑实现都很简单,多想多思考多练习,你会越来越棒的!

    展开全文
  • 微信小程序获取用户IP地址,HTTPS接口 很简单实用的ip地址接口, 只返回当前ip 接口返回内容格式为: {“ip”:“27.211.239.98”} // 获取IP地址 wx.request({ url: 'https://tianqiapi.com/ip/', data: { }, ...

    微信小程序获取用户IP地址,HTTPS接口

    很简单实用的ip地址接口, 只返回当前ip
    接口返回内容格式为:
    {“ip”:“27.211.239.98”}

    // 获取IP地址
    wx.request({
      url: 'https://tianqiapi.com/ip/',
      data: {
      },
      method: 'POST',
      header: {
        'content-type': 'application/x-www-form-urlencoded'
      },
      success: function (res) {
        console.log('IP地址: ' + res.data.ip);
      }
    });
    
    

    温馨提醒
    如果是测试, 请勾选配置 不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书
    如果正式使用, 请添加安全域名 ( tianqiapi.com )

    ————————————————
    版权声明:本文为CSDN博主「Cc琎」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/qq_38832501/article/details/92074616

    展开全文
  • springboot项目,h5页面通过微信公众号获取微信用户信息 最近本人有一个项目需求,微信公众号里点击一个菜单进入一个商城购物系统。 对于在微信公众号还是小白的我来说难度有点大,但是做完后发现也就这样,用多了就...

    springboot项目,h5页面通过微信公众号获取微信用户信息
    最近本人有一个项目需求,微信公众号里点击一个菜单进入一个商城购物系统。
    对于在微信公众号还是小白的我来说难度有点大,但是做完后发现也就这样,用多了就熟悉了。下面记录一下自己开发过程中遇到的一些问题以及解决方案。有好多也是自己在网上找的资料,自己慢慢整合起来的。所以你可能会看到好多差不多的代码。
    准备工作:
    首先搭建springboot+shiro权限管理框架,在此基础上开发微信H5页面以及商城的后台管理系统。使用MySQL数据库。开发工具idea。
    在github上找了一个springboot+shiro后台管理项目。本人觉得简洁,实用,附上链接
    https://blog.csdn.net/zwzw1219/article/details/81813201
    项目框架好了,然后H5页面在网上找了一个简单的商城模板。该H5模板也是自己在CSDN上面花积分下载下来的。该模板还是有些小问题的,需要自己去修改。
    模板链接: https://pan.baidu.com/s/1k-bjTtbW9lDB66bP1ESWmA 提取码: bvrr 复制这段内容后打开百度网盘手机App,操作更方便哦
    HBuilderX工具链接: https://pan.baidu.com/s/1F6XYM1Z4u2NMaa7QHqCPKQ 提取码: wime 复制这段内容后打开百度网盘手机App,操作更方便哦
    项目框架有了,前端页面也有了,接下来准备微信公众号(自己申请一个微信测试公众号,然后在里面给自己开发者权限,这样才能再微信web开发者工具本地调试)
    附上操作流程:
    1.自己准备一个带域名的服务器资源。因为微信公众号需要域名。
    我自己没有去弄域名了,而且麻烦不方便本地开发,所以在网上找了一个内网穿刺工具,每天有8个小时的免费使用时间。如果当中不能使用域名后,关掉重启,重新敲命令,获取域名。同时微信公众平台接口测试账号里面也要修改域名。
    附上链接: https://pan.baidu.com/s/1i1zZwC1IJe3NQXlEmIUc1w 提取码: php6 复制这段内容后打开百度网盘手机App,操作更方便哦
    2.进入微信公众平台接口测试帐号申请
    https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
    在这里插入图片描述
    直接点击登录,手机微信端确认
    在这里插入图片描述
    登录后,拿到APPID和appsecret 去微信公众平台调试工具获取token
    http://mp.weixin.qq.com/debug/cgi-bin/apiinfo
    在这里插入图片描述
    接着到微信公众平台测试号管理,也就刚刚的第一个微信链接
    在这里插入图片描述
    这个接口配置信息 URL为项目微信用户授权页面(域名+项目文件)
    token为上面的token。(我的一直配置失败,但是后面发现没有影响到本地开发)
    在这里插入图片描述
    点击修改,可以修改域名
    此域名为 内网穿刺工具生成的域名 敲命令 ngrok http 本地项目端口号
    在这里插入图片描述
    在这里插入图片描述
    扫码,添加微信测试公众号。
    然后 体验接口权限表–网页服务–网页帐号–网页授权获取用户基本信息–修改
    在这里插入图片描述
    此域名和之前的那个一样。

    准备了这么多后,开始代码了

    微信授权接口js,该js我放在了访问进来的首页.html

    $(document).ready(function() {
        center.enterWxAuthor();
    })
    // 自己的那个微信appid
    var WX_APPID = "wx8eXXXXXXX68aa";
    // 此路径需和微信接口配置一样
    var pageUrl = pathUrl + "pages/shop/shop_index.html";
    var center = {
        init: function(){
            // 渲染首页
            console.log("渲染首页");
        },
        enterWxAuthor: function(){
            debugger
            var wxUserInfo = localStorage.getItem("wxUserInfo");
            if (!wxUserInfo) {
                var code = getUrlParam('code');
                if (code) {
                    getWxUserInfo(code);
                    center.init();
                }else{
                    //没有微信用户信息,没有授权-->> 需要授权,跳转授权页面
                    var authorizeUrl ='https://open.weixin.qq.com/connect/oauth2/authorize?appid='+ WX_APPID+'&redirect_uri='+ pageUrl+'&response_type=code&scope=snsapi_userinfo#wechat_redirect';
                    window.location.href =authorizeUrl;
                }
            }else{
                center.init();
            }
        }
    }
    
    
    function getWxUserInfo(par){
        var code = getUrlParam("code");
        if (par) code = par;
        var authorizationUrl = pathUrl + "shopApi/authorization";
        $.get(authorizationUrl,{code:code},function (data) {
            //保证写入的wxUserInfo是正确的
            if(data.status == 200){
                localStorage.setItem("wechatUserid",data.data.id);
                localStorage.setItem('wxUserInfo',JSON.stringify(data.data));//写缓存--微信用户信息
            }
    
        },"json");
    
    }
    

    common.js 自己取舍相关代码

    //form序列化为json
    $.fn.serializeObject = function()
    {
        var o = {};
        var a = this.serializeArray();
        $.each(a, function() {
            if (o[this.name] !== undefined) {
                if (!o[this.name].push) {
                    o[this.name] = [o[this.name]];
                }
                o[this.name].push(this.value || '');
            } else {
                o[this.name] = this.value || '';
            }
        });
        return o;
    };
    
    //获取url后的参数值
    function getUrlParam(key) {
    	var href = window.location.href;
    	var url = href.split("?");
    	if(url.length <= 1){
    		return "";
    	}
    	var params = url[1].split("&");
    	
    	for(var i=0; i<params.length; i++){
    		var param = params[i].split("=");
    		if(key == param[0]){
    			return param[1];
    		}
    	}
    }
    
    
    // Get Root Dir
    getRootDir = function (js) {
        var path = "";
        var strFullPath = window.document.location.href;
        var strPath = window.document.location.pathname;
        var pos = strFullPath.indexOf(strPath);
        var prePath = strFullPath.substring(0, pos);
        var postPath = strPath.substring(0, strPath.substr(1).indexOf('/') + 1);
        var path = prePath + postPath + "/";
        return path;
    }
    
    getRootDirURL = function (js) {
        var path = "";
        var strFullPath = window.document.location.href;
        var strPath = window.document.location.pathname;
        var pos = strFullPath.indexOf(strPath);
        var prePath = strFullPath.substring(0, pos);
        var path = prePath + "/";
        return path;
    }
    
    // 项目根目录
    var projectPath = getRootDir("common.js");
    var pathUrl = getRootDirURL("common.js");
    var imagePath = getRootDir("common.js");
    // 手机号
    var mobileReg = /^1[3|4|5|7|8]\d{9}$/;
    // 邮箱
    var emailReg = /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/;
    // 邮编
    var zipcodeReg = /[1-9]\d{5}(?!\d)/;
    // 正整数
    var regPositive = /^[1-9]\d*$/;
    //整数
    var regInteger = /^[0-9]*$/;
    // IP地址
    var ipReg = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/;
    // 身份证号码为15位或者18位,15位时全为数字,18位前17位为数字,最后一位是校验位,可能为数字或字符X
    var iDReg = /^([0-9]{17}[0-9X]{1})|([0-9]{15})$/;
    // 英文
    var englishReg = /[a-zA-Z]/;
    // 中文
    var cnReg = /[\u4e00-\u9fa5]/;
    // 正数金额
    var regAmount = /(^[1-9](\d+)?(\.\d{1,2})?$)|(^0$)|(^\d\.\d{1,2}$)/ ;
    
    (function ($) {
        $.extend({
            // 替换全部
            replaceAll: function (str, str1, str2) {
                return str.replace(new RegExp(str1, "gm"), str2);
            },
            // 为空检查
            checkNull: function (obj) {
                return !$.trim(obj);
            },
            // 手机号检查
            checkMobile: function (obj) {
                return !(mobileReg.test(obj));
            },
            // 邮箱检查
            checkEmail: function (obj) {
                return !(emailReg.test(obj));
            },
            // 邮编检查
            checkZipcode: function (obj) {
                return !(zipcodeReg.test(obj));
            },
            // 正整数检查
            checkPositive: function (obj) {
                return !(regPositive.test(obj));
            },
            // IP地址检查
            checkIp: function (obj) {
                return !(ipReg.test(obj));
            },
            // 身份证检查
            checkID: function (obj) {
                return !(iDReg.test(obj));
            },
            // 英文检查
            checkEn: function (obj) {
                return !(englishReg.test(obj));
            },
            // 中文检查
            checkEn: function (obj) {
                return !(cnReg.test(obj));
            },
            // 正整数金额
            checkAmount: function (obj) {
                return !(regAmount.test(obj));
            }
        });
    })(jQuery);
    
    // 日期比较yyyy-MM-dd
    function dateCompare(startDate, endDate) {
        if (startDate == '' || endDate == '') {
            return;
        }
        var arr = startDate.split("-");
        var starttime = new Date(arr[0], arr[1], arr[2]);
        var starttimes = starttime.getTime();
    
        var arrs = endDate.split("-");
        var lktime = new Date(arrs[0], arrs[1], arrs[2]);
        var lktimes = lktime.getTime();
    
        if (starttimes >= lktimes) {
            return true;
        } else {
            return false;
        }
    }
    
    function checkNull(val) {
        if (val == null || $.trim(val).length == 0) {
            return true;
        }
        return false;
    }
    
    //手机号检查
    function checkMobile(obj) {
        return !(mobileReg.test(obj));
    }
    
    // 邮箱检查
    function checkEmail(obj) {
        return !(emailReg.test(obj));
    }
    
    // 邮编检查
    var zipReg = /^[1-9][0-9]{5}$/;
    
    function checkZipcode(obj) {
        return !(zipReg.test(obj));
    }
    
    // 正整数检查
    function checkPositive(obj) {
        return !(regPositive.test(obj));
    }
    
    // 整数检查
    function checkInteger(obj) {
        return !(regInteger.test(obj));
    }
    
    // IP地址检查
    function checkIp(obj) {
        return !(ipReg.test(obj));
    }
    
    // 身份证检查
    function checkID(obj) {
        return !(iDReg.test(obj));
    }
    
    // 英文检查
    function checkEn(obj) {
        return !(englishReg.test(obj));
    }
    
    // 中文检查
    function checkCh(obj) {
        return !(cnReg.test(obj));
    }
    
    // 正整数金额
    function checkAmount(obj) {
        return !(regAmount.test(obj));
    }
    
    // 小数检查
    var pointReg = /^\d+\.\d+$/;
    
    function checkPoint(obj) {
        return !(pointReg.test(obj));
    }
    
    //验证年月日(yyyy-mm-dd)格式
    function isDate(dateString) {
        var r = dateString.match(/^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2})$/);
        if (r == null) {
            return false;
        }
        var d = new Date(r[1], r[3] - 1, r[4]);
        var num = (d.getFullYear() == r[1] && (d.getMonth() + 1) == r[3] && d.getDate() == r[4]);
        return (num != 0);
    }
    
    

    ShopApiController

        /**
         * @Author zhangfeng
         * @Description //TODO 首页 获取微信用户信息
         * @Date 2019/5/23 14:00
         * @Param [code, request, response]
         * @return com.otfresh.utils.ServerResponse
         **/
        @GetMapping("/authorization")
        @ResponseBody
        public ServerResponse authorizationWeixin( @RequestParam String code,HttpServletRequest request,HttpServletResponse response) throws IOException {
            request.setCharacterEncoding("UTF-8");
            response.setCharacterEncoding("UTF-8");
            try {
                return  iWechatUserService.getOauthAccessToken(code);
            } catch (Exception e) {
                logger.error("RestFul of authorization is error.",e);
            }
            return ServerResponse.createByError();
        }
    

    ServerResponse.java 为返回工具类,需要的朋友可以自己保存

    package com.otfresh.utils;
    
    import com.fasterxml.jackson.annotation.JsonFormat;
    import com.fasterxml.jackson.annotation.JsonIgnore;
    import com.fasterxml.jackson.annotation.JsonInclude;
    import com.fasterxml.jackson.annotation.JsonInclude.Include;
    
    import java.util.Date;
    
    ;
    
    /**
     * 
     * { data: status/code: msg:
     * 
     * }
     * 
     * 统一返回值
     * 
     * @author Administrator
     * @param
     */
    
    //将该标记放在属性上,如果该属性为NULL则不参与序列化 
    //如果放在类上边,那对这个类的全部属性起作用 
    //Include.Include.ALWAYS 默认 
    //Include.NON_DEFAULT 属性为默认值不序列化 
    //Include.NON_EMPTY 属性为 空(“”) 或者为 NULL 都不序列化 
    //Include.NON_NULL 属性为NULL 不序列化 
    @JsonInclude(Include.NON_NULL)
    public class ServerResponse {
    
    	private int status;
    	private String msg;
    	private String field;
    	private Object data;
    
    	// 私有构造函数
    	private ServerResponse(int status) {
    		this.status = status;
    	}
    
    	// 私有构造函数
    	private ServerResponse(int status, Object data) {
    		this.status = status;
    		this.data = data;
    	}
    	
    
    	// 私有构造函数
    	private ServerResponse(int status, String msg, Object data) {
    		this.status = status;
    		this.msg = msg;
    		this.data = data;
    	}
    
    	// 私有构造函数
    	private ServerResponse(int status, String msg) {
    		this.status = status;
    		this.msg = msg;
    	}
    	
    	// 验证私有构造函数
    	private ServerResponse(int status, String field, String msg, Object data) {
    		this.status = status;
    		this.field = field;
    		this.msg = msg;
    		this.data = data;
    	}
    
    	// 使之不在json序列化结果当中
    	@JsonIgnore
    	public boolean isSuccess() {
    		return this.status == ResponseCode.SUCCESS.getCode();
    	}
    
    	@JsonFormat(pattern = "yyyy/MM/dd HH:mm:ss")
    	public Date getDate() {
    		return new Date();
    	}
    
    	public int getStatus() {
    		return status;
    	}
    
    	public Object getData() {
    		return data;
    	}
    
    	public String getMsg() {
    		return msg;
    	}
    
    	public String getField() {
    		return field;
    	}
    
    	// 正确返回
    	public static ServerResponse createBySuccess() {
    		return new ServerResponse(ResponseCode.SUCCESS.getCode());
    	}
    
    	public static ServerResponse createBySuccessMessage(String msg) {
    		return new ServerResponse(ResponseCode.SUCCESS.getCode(), msg);
    	}
    
    	public static ServerResponse createBySuccess(Object data) {
    		return new ServerResponse(ResponseCode.SUCCESS.getCode(), data);
    	}
    
    	public static ServerResponse createBySuccess(String msg, Object data) {
    		return new ServerResponse(ResponseCode.SUCCESS.getCode(), msg, data);
    	}
    
    	public static ServerResponse createBySuccess(ResponseCode responseCode) {
    		return new ServerResponse(responseCode.getCode(), responseCode.getDesc());
    	}
    
    	public static ServerResponse createBySuccess(ResponseCode responseCode, Object data) {
    		return new ServerResponse(responseCode.getCode(), responseCode.getDesc(), data);
    	}
    
    	// error返回
    	public static ServerResponse createByError() {
    		return new ServerResponse(500, ResponseCode.ERROR.getDesc());
    	}
    
    	public static ServerResponse createByErrorMessage(String errorMessage) {
    		return new ServerResponse(ResponseCode.ERROR.getCode(), errorMessage);
    	}
    
    	public static ServerResponse createByErrorCodeMessage(int errorCode, String errorMessage) {
    		return new ServerResponse(errorCode, errorMessage);
    	}
    
    	public static ServerResponse createByErrorCodeMessage(ResponseCode responseCode) {
    		return new ServerResponse(responseCode.getCode(), responseCode.getDesc());
    	}
    	
    	public static ServerResponse createByErrorValidator(int code,String field,String message) {
    		return new ServerResponse(code, field,message,null);
    	}
    	
    	public static ServerResponse createByErrorValidator(int code,String field,String message,Object data) {
    		return new ServerResponse(code, field,message,data);
    	}
    
    }
    
    

    ResponseCode.java

    package com.otfresh.utils;
    
    /**
     * Created by geely enum类
     */
    public enum ResponseCode {
    
    	SUCCESS(200, "SUCCESS"), ERROR(400, "ERROR"), 
    	NEED_LOGIN(100, "NEED_LOGIN"), 
    	ERROR_LOGIN(401, "你输入的账号和密码有误!!"),
    	ERROR_CODE_LOGIN(402, "你输入的验证有误!!"), 
    	SESSION_FAIIL(101, "SESSION IS CLOSED"), 
    	ILLEGAL_ARGUMENT(202, "ILLEGAL_ARGUMENT");
    
    	private final int code;
    	private final String desc;
    
    	ResponseCode(int code, String desc) {
    		this.code = code;
    		this.desc = desc;
    	}
    
    	public int getCode() {
    		return code;
    	}
    
    	public String getDesc() {
    		return desc;
    	}
    
    }
    

    IWechatUserService.java

    /**
    	 * 根据code 获取授权的token 仅限授权时使用,与全局的access_token不同
    	 * @param code
    	 * @return String 用户信息
    	 * @throws IOException
    	 * @throws ClientProtocolException
    	 */
    	ServerResponse getOauthAccessToken(String code) throws Exception;
    

    WechatUserServiceImpl.java

    package com.otfresh.service.impl;
    
    
    import com.alibaba.fastjson.JSONObject;
    import com.otfresh.dao.WechatUserDao;
    import com.otfresh.model.dto.WechatUserDTO;
    import com.otfresh.model.po.AccessTokenDO;
    import com.otfresh.model.vo.WechatUserVO;
    import com.otfresh.service.IAccessTokenService;
    import com.otfresh.service.IWechatUserService;
    import com.otfresh.utils.ServerResponse;
    import com.otfresh.utils.StringUtil;
    import com.otfresh.utils.constants.StatusEnum;
    import org.apache.http.client.ClientProtocolException;
    import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.ssl.TrustStrategy;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    import org.springframework.web.client.RestTemplate;
    
    import javax.net.ssl.SSLContext;
    import java.io.IOException;
    import java.security.KeyManagementException;
    import java.security.KeyStoreException;
    import java.security.NoSuchAlgorithmException;
    import java.security.cert.X509Certificate;
    import java.util.*;
    
    
    /**
     * 微信用户模块 Service 实现层
     * @author zhangfeng
     * @create 2019年05月22日 09:56:34
     **/
    @Service
    public class WechatUserServiceImpl implements IWechatUserService  {
    
    	protected final Logger logger = LoggerFactory.getLogger(this.getClass());
    
    	@Value("${app.WX_APPID}")
    	private String WX_APPID;
    	@Value("${app.WX_APPSECRET}")
    	private String WX_APPSECRET;
    	@Value("${app.WX_OAUTH_ACCESS_TOKEN_URL}")
    	private String WX_OAUTH_ACCESS_TOKEN_URL ;
    	@Value("${app.WX_OAUTH_REFRESH_TOKEN_URL}")
    	private String WX_OAUTH_REFRESH_TOKEN_URL ;
    	@Value("${app.WX_USERINFO_URL}")
    	private String WX_USERINFO_URL ;
    
    	@Autowired
    	private WechatUserDao wechatUserDao;
    
    	@Autowired
    	private IAccessTokenService accessTokenService;
    
    
    	/**
    	 * @Author zhangfeng
    	 * @Description //TODO 更新微信用户信息
    	 * @Date 2019/5/23 9:27
    	 * @Param [wechatUserDTO]
    	 * @return WechatUserDTO
    	 **/
    	@Transactional(rollbackFor = Exception.class)
    	public WechatUserDTO saveOrUpdateWechatUseer(String user){
    		JSONObject userJson = JSONObject.parseObject(user);
    		String openid = userJson.getString("openid");
    		String nickname = userJson.getString("nickname");
    		String sex = userJson.getString("sex");
    		String headimgurl = userJson.getString("headimgurl");
    
    		WechatUserDTO wechatUserDTO = new WechatUserDTO();
    		wechatUserDTO.setOpenid(openid);
    		wechatUserDTO.setWechatName(nickname);
    		wechatUserDTO.setHeadImg(headimgurl);
    		if(userJson.containsKey("unionid")){
    			String unionid = userJson.getString("unionid");
    			wechatUserDTO.setWechatNo(unionid);
    		}
    		// 查询是否存在该用户
    		WechatUserVO wechatUserByOpenId = wechatUserDao.getWechatUserByOpenId(wechatUserDTO);
    		if(StringUtil.isNotBlank(wechatUserByOpenId)){
    			wechatUserDTO.setId(wechatUserByOpenId.getId());
    			wechatUserDTO.setUpdateTime(new Date());
    			wechatUserDTO.setLastLoginTime(new Date());
    			// 更新信息
    			wechatUserDao.updateWechatUser(wechatUserDTO);
    		}else{
    			wechatUserDTO.setStatus(StatusEnum.NEW.getKey().toString());
    			wechatUserDTO.setSex(sex);
    			// 新增信息
    			wechatUserDao.saveWechatUser(wechatUserDTO);
    		}
    		return wechatUserDTO;
    	}
    
    
    	/**
    	 * 根据code 获取授权的token 仅限授权时使用,与全局的access_token不同
    	 * @param code
    	 * @return
    	 * @throws IOException
    	 * @throws ClientProtocolException
    	 */
    	@Override
    	@Transactional(rollbackFor = Exception.class)
    	public ServerResponse getOauthAccessToken(String code) throws Exception {
    		// 从数据库表查询token信息
    		AccessTokenDO accessToken = accessTokenService.getAccessTokenById(1);
    		String rs_access_token = null;
    		String rs_openid = null;
    		//通过code换取网页授权access_token
    		String url = WX_OAUTH_ACCESS_TOKEN_URL + "?appid="+WX_APPID+"&secret="+WX_APPSECRET+"&code="+code+"&grant_type=authorization_code";
    		// 如果token为null 或者 超过过期时间
    		if(accessToken == null || accessToken.getCreateTime().getTime() + Long.parseLong(accessToken.getExpiresIn()) *1000 < System.currentTimeMillis()){
    			synchronized (this) {
    				//已过期,需要刷新
    				String rh = restTemplate().getForObject(url, String.class);
    				JSONObject json = JSONObject.parseObject(rh);
    				if(json.containsKey("errcode")){
    					return ServerResponse.createByErrorCodeMessage(Integer.parseInt(json.get("errcode").toString()),json.get("errmsg").toString());
    				}
    				// 如果token为null 则不刷新token
    				if(accessToken == null ){
    					String access_token = json.getString("access_token");
    					String expires_in = json.getString("expires_in");
    					rs_openid = json.getString("openid");
    					rs_access_token = access_token;
    					accessToken = new AccessTokenDO();
    					accessToken.setId(1);
    					accessToken.setAccessToken(access_token);
    					accessToken.setExpiresIn(expires_in);
    					accessTokenService.saveAccessToken(accessToken);
    				}else{
    					String refresh_token = json.getString("refresh_token");
    					// 刷新access_token
    					String refresh_url = WX_OAUTH_REFRESH_TOKEN_URL+"?appid="+WX_APPID+"&grant_type=refresh_token&refresh_token="+refresh_token;
    					String r_rh = restTemplate().getForObject(refresh_url, String.class);
    					JSONObject r_json = JSONObject.parseObject(r_rh);
    					if(r_json.containsKey("errcode")){
    						return ServerResponse.createByErrorCodeMessage(Integer.parseInt(r_json.get("errcode").toString()),r_json.get("errmsg").toString());
    					}
    
    					String r_access_token = r_json.getString("access_token");
    					String r_expires_in = r_json.getString("expires_in");
    					rs_openid = r_json.getString("openid");
    					rs_access_token = r_access_token;
    
    					accessToken = new AccessTokenDO();
    					accessToken.setId(1);
    					accessToken.setAccessToken(r_access_token);
    					accessToken.setExpiresIn(r_expires_in);
    					accessTokenService.updateAccessToken(accessToken);
    				}
    			}
    		}else{
    			//还没有过期
    			String rh = restTemplate().getForObject(url, String.class);
    			JSONObject json = JSONObject.parseObject(rh);
    			if(json.containsKey("errcode")){
    				return ServerResponse.createByErrorCodeMessage(Integer.parseInt(json.get("errcode").toString()),json.get("errmsg").toString());
    			}
    			rs_access_token = json.getString("access_token");
    			rs_openid = json.getString("openid");
    		}
    		return getOauthUserInfo(rs_access_token,rs_openid);
    	}
    
    	/**
    	 * 根据授权token获取用户信息
    	 * @param access_token
    	 * @param openid
    	 * @return
    	 */
    	@Transactional(rollbackFor = Exception.class)
    	public ServerResponse getOauthUserInfo(String access_token,String openid)  {
    		String url = WX_USERINFO_URL +"?access_token="+ access_token +"&openid="+ openid +"&lang=zh_CN";
    		try {
    			String user = restTemplate().getForObject(url, String.class);
    			user = new String(user.getBytes("ISO-8859-1"), "UTF-8");
    			JSONObject userJson = JSONObject.parseObject(user);
    			if(userJson.containsKey("errcode")){
    				return ServerResponse.createByErrorCodeMessage(Integer.parseInt(userJson.get("errcode").toString()),userJson.get("errmsg").toString());
    			}
    			//保存用户信息
    			WechatUserDTO wechatUserDTO = this.saveOrUpdateWechatUseer(user);
    			return ServerResponse.createBySuccess(wechatUserDTO);
    		} catch (Exception e) {
    			logger.error("RestFul of authorization is error.",e);
    		}
    		return ServerResponse.createByError();
    	}
    
    // 使用spring的RestTemplate 进行https请求 ,不懂的可以在网上搜索RestTemplate 
    	public static RestTemplate restTemplate() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
    		TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
    		SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
    				.loadTrustMaterial(null, acceptingTrustStrategy)
    				.build();
    		SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
    		CloseableHttpClient httpClient = HttpClients.custom()
    				.setSSLSocketFactory(csf)
    				.build();
    		HttpComponentsClientHttpRequestFactory requestFactory =
    				new HttpComponentsClientHttpRequestFactory();
    		requestFactory.setHttpClient(httpClient);
    		RestTemplate restTemplate = new RestTemplate(requestFactory);
    		return restTemplate;
    	}
    }
    

    IAccessTokenService 为保存accessToken 而设计的。本人用的spring 的 ehcache缓存技术+数据表保存accessToken ,当然此处也可以使用redis。网上也有这种方案,本文不再记录。附上本人参考的链接https://blog.csdn.net/jiepan9178/article/details/81449004
    注解形式获取参数,注意发布到测试环境或者真实环境微信APPID和appsecret需要根据自己的实际情况填写
    application.properties

    # 微信appId 和appsecret
    app.WX_APPID=wxc524XXXXXXXXX0b8
    app.WX_APPSECRET=901XXXXXXXXXXXXXXXXe2e00
    #通过code换取网页授权access_token Url
    app.WX_OAUTH_ACCESS_TOKEN_URL=https://api.weixin.qq.com/sns/oauth2/access_token
    #刷新access_token url
    app.WX_OAUTH_REFRESH_TOKEN_URL=https://api.weixin.qq.com/sns/oauth2/refresh_token
    #获取微信用户 url
    app.WX_USERINFO_URL = https://api.weixin.qq.com/sns/userinfo
    

    其中的实体相关类和service类,dao层,mapper,SQL就不贴代码了无非就是CRUD,主要核心代码是getOauthAccessToken这个方法。

    好了,代码都准备了好了,那开始来测试了
    测试工具为 微信web开发者工具,账号就是之前设置开发者权限的微信账号登录。选择公众号网页调试。地址栏输入 之前在微信公众平台测试号 里面设置的回调域名 + 项目的访问页面。然后就可以调试了。
    以上自己测的没有问题,但是难保在诸位博友的项目中会出现各种问题,遇到问题不要急,一步一步慢慢解决。本人在编写这部分代码时,因为不懂,出现过各种问题,比如微信开发者工具无法正常访问本地网页,无法获取微信用户信息等等。最后都一步一步慢慢解决了。该代码块目前只在本地开发过,还没有发布到测试环境使用,估计还会有坑!!!!!!
    好了,本地开发获取微信用户信息的相关代码就到这里了,本人小白一个,代码有不正确的地方还请各位博友指出。

    展开全文
  • 微信h5静默、非静默授权获取用户openId的方法和步骤: 一、openId是什么? openId是用户在当前公众号下的唯一标识(‘身份证’),就是说通过这个openId,就能区分在这个公众号下具体是哪个用户。 二、openId有什么用...
  • 因项目需要,需在微信浏览器中获取实时位置。使用微信jweixin-1.2.0.js初始化时(wx.config)需要签名、appID,URL等参数,本文将讲解测试环境下,初始化各项测试数据的生成。如:公众号的测试appID,appSecret,域名的...
  • 微信公众号获取用户当前经纬度

    千次阅读 2019-07-18 16:48:22
    php, 第一步:先封装一个类(本人用的TP5,阅读者参考类里面的类容即可) <?php namespace app\shangjia\controller; use app\common\controller\Base; class JSSDK extends Base { private $appId; private...
  • // succ.wxml <view>手机IP:{{motto.query}}</view> // succ.js var app = getApp() Page({ data: { ... motto: '' // IP地址 ... onLoad: function (e) { // 获取参数 var that =...
  • 穿透代理获取用户真实IP地址

    千次阅读 2018-10-23 11:05:27
    在对接微信H5支付API时,有一关键步骤是获取用户的真实IP微信开发文档给出的解释为: H5支付要求商户在统一下单接口中上传用户真实ip地址“spbill_create_ip”, 为保证微信端获取用户ip地址与商户端获取的...
  • 微信h5静默、非静默授权获取用户openId的方法和步骤: 一、openId是什么? openId是用户在当前公众号下的唯一标识(‘身份证’),就是说通过这个openId,就能区分在这个公众号下具体是哪个用户。 二、openId有...
  • 微信h5静默、非静默授权获取用户openId的方法和步骤: 一、openId是什么? openId是用户在当前公众号下的唯一标识(‘身份证’),就是说通过这个openId,就能区分在这个公众号下具体是哪个用户。 二、openId有...
  • 浏览器原生跟微信JS-SDK两种方法获取用户经纬度和所在城市的方法 www.MyException.Cn 网友分享于:2015-09-24 浏览:0次 浏览器原生和微信JS-SDK两种方法获取用户经纬度和所在城市的方法 网上找了很多...
  • 微信公众号开发基本流程

    万次阅读 多人点赞 2019-04-26 09:40:21
    过年前后做了个微信公众号项目,已经过去一段时间了,抽空回忆总结下基本流程吧,不然很快估计自己就忘了。。 微信公众平台官网:https://mp.weixin.qq.com 文章目录一、注册公众号二、了解公众号管理页面三、必备...
  • 先熟悉此文档开发者模式的网页授权 具体而言,网页授权流程分为四步: 1、引导用户进入授权页面同意授权,获取code ...4、通过网页授权access_token和openid获取用户基本信息(支持UnionID机制) 前提以获取开发...
  • 如标题,获取openid的前提条件是: 1、在微信公众号上要有域名注册,也就是你项目部署的服务器对应的域名,IP可以吗?不行,必须是域名。 2、项目服务端口必须80端口(在服务器可以利用nginx转发的方式配置80...
  • 图中是前端页面第一步骤单点登录的地址,其中的scope、redirect_uri最为重要,一个是获取用户基本信息的权限,一个是微信端跳转到你登录页面,然后会带入code和state字段给我们的页面。 编写我们登录页面基础逻辑是...
  • .net C#微信公众号开发

    千次阅读 2020-06-17 16:32:09
    打开微信公众平台,主页左侧找到 “开发”栏目,选择基本配置,获取AppId,appsecret。 开发者密码需要管理员授权查看。 二、服务器配置 1、主页左侧找到 “开发”栏目,选择基本配置,下半页“服务器配置”模块...
  • 微信开发-公众号支付(1)-获取openid

    千次阅读 2017-10-31 15:40:29
    微信开发-公众号支付(1)-获取openid记录下开发微信支付过程中踩过的坑。微信公众号支付开发之前,需要准备的东西APPID , APPSECRET , PAYKEY 注意:此处的公众平台和商户平台必须是绑定的appid 和 appsecret 可以从...
  • 先参考CSDN里已有的资料学起:微信开发学习路线 一、 服务号/订阅号/企业号区别 关于文章里说的不容易认证这个事情,笔者所在的公司申请很顺利,并不困难~ 认证流程、认证条件以及认证后可实现的功能请参照微信...
  • 微信开发之Curl

    2019-11-28 17:39:11
    微信开发过程当中: 使用开发模式创建微信自定义菜单,需要模拟HTTPS的 POST请求,这里就需要使用PHP的curl函数。 另外好多接口也要用到curl函数,因此curl函数是微信开发的基础,必须熟练掌握。 2.学习内容 1、...
1 2 3 4 5 ... 20
收藏数 9,264
精华内容 3,705
关键字:

微信开发获取用户端ip