转载:微信开放平台开发第三方受权登录(二):PC网页端

微信开放平台开发第三方受权登录(二):PC网页端

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处连接和本声明。
本文连接: http://www.javashuo.com/article/p-hlrkqhfr-hv.html

微信开放平台开发系列文章:

微信开放平台开发第三方受权登录(一):开发前期准备html

微信开放平台开发第三方受权登录(二):PC网页端java

微信开放平台开发第三方受权登录(三):Android客户端web

微信开放平台开发第三方受权登录(四):微信公众号redis

微信开放平台开发第三方受权登录(五):微信小程序spring

 

目录数据库

1、需求apache

2、开发流程json

1.网站应用:(微信客户端扫码受权登录)小程序

3、开发使用的技术及工具微信小程序

4、具体实现步骤

一、网站应用

1)请求获取Code

2)用户赞成受权与否

3)获取access_token

4)经过access_token调用接口获取用户我的信息(UnionID机制)

5)刷新access_token

5、测试结果

一、网站应用

6、应用关键参数位置


微信开放平台第三方受权登录开发文档(PC网页端)

  当微信开放平台开发第三方受权登录(一):开发前期准备完成后,已经获取到应用的AppID和AppSecret、且已经成功申请到微信登录功能。能够进行第三方登录受权开发。

网站应用微信登陆是基于OAuth2.0协议标准构建的微信OAuth2.0受权登陆系统。

1、需求

根据需求,须要拥有第三方微信登陆功能,并获取到用户信息。

2、开发流程

1.网站应用:(微信客户端扫码受权登录)

1)第三方发起微信受权登陆请求,微信用户容许受权第三方应用后,微信会拉起应用或重定向到第三方网站,而且带上受权临时票据code参数;

2)经过code参数加上AppID和AppSecret等,经过API换取access_token;

3)经过access_token进行接口调用,获取用户基本数据资源或帮助用户实现基本操做。

网站应用第三方受权登录获取用户信息

3、开发使用的技术及工具

一、使用IDEA2017.2进行开发

二、使用SpringBoot进行快速开发

三、使用redis进行缓存。

四、使用fastJson对json数据进行处理

五、使用Maven对项目进行管理

4、具体实现步骤

一、网站应用

建立工程

打开IDEA,新建一个工程,选择Spring Initializr,Next。而后填写工程基本信息

选择SpringBoot的版本已经须要添加的依赖,也能够直接跳过,手动添加依赖。因为是web工程,须要添加web相关依赖。模板引擎采用springboot推荐的thymeleaf。最后点击确认,进入工程。

 

添加相关依赖

  1.    <dependency>
  2.       <groupId>org.apache.commons</groupId>
  3.       <artifactId>commons-lang3</artifactId>
  4.       <version>3.5</version>
  5.    </dependency>
  6.    <dependency>
  7.       <groupId>com.alibaba</groupId>
  8.       <artifactId>fastjson</artifactId>
  9.       <version>1.2.4</version>
  10.    </dependency>
  11.    <!-- 添加httpclient支持 -->
  12.    <dependency>
  13.       <groupId>org.apache.httpcomponents</groupId>
  14.       <artifactId>httpclient</artifactId>
  15.       <version>4.5.2</version>
  16.    </dependency>
  17.    <dependency>
  18.       <groupId>redis.clients</groupId>
  19.       <artifactId>jedis</artifactId>
  20.       <version>2.8.1</version>
  21.       <type>jar</type>
  22.    </dependency>

添加配置文件

SpringBoot默认会将resources下的application名字开头的properties做为配置文件。因此只须要添加application.properties就能够了

因为是使用thymeleaf做为模板引擎。能够添加相应的配置:

  1. #thymelea模板配置
  2. spring.thymeleaf.prefix=classpath:/templates/
  3. spring.thymeleaf.suffix=.html
  4. spring.thymeleaf.mode=HTML5
  5. spring.thymeleaf.encoding=UTF -8
  6. spring.thymeleaf.content-type= text/html
  7. spring.thymeleaf.cache= false
  8. spring.resources.chain.strategy.content.enabled= true
  9. spring.resources.chain.strategy.content.paths=/**

为了让系统更具备通用性,分别建立application-dev.properties、application-prod.properties对不一样的环境进行配置。

在application.properties中,使用spring.profiles.active进行配置环境的选择。

如:spring.profiles.active = prod

 

如:application-prod.properties

  1. ## 微信开放平台
  2. # APPID
  3. wechat.open.appid =
  4. # APPSECRET
  5. wechat.open.appsecret =
  6. # 回调地址
  7. wechat.open.redirect_uri =

新建javaBean:WeChatUserInfo.java

  1. @Getter @Setter @ToString
  2. public class WeChatUserInfo {
  3.     String openid;
  4.     String nickname;
  5.     Integer sex;
  6.     String province;
  7.     String city;
  8.     String country;
  9.     String headimgurl;
  10.     String privilege;
  11.     String unionid;
  12.  
  13. }

新建WeChatOpenLoginController.java实现微信开放平台第三方登陆的主要逻辑。

根据文档进行编写代码。

 

1)请求获取Code

前提:应用已经获取相应的网页受权做用域(scope=snsapi_login)

开发:第三方网站引导用户打开连接

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

参数说明:

参数

必须

说明

appid

应用惟一标识

redirect_uri

请使用urlEncode对连接进行处理

response_type

填code

scope

应用受权做用域,拥有多个做用域用逗号(,)分隔,网页应用目前仅填写snsapi_login便可

state

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

 

注意:若提示“该连接没法访问”,请检查参数是否填写错误,如redirect_uri的域名与审核时填写的受权域名不一致或scope不为snsapi_login。


  

  1.   @RequestMapping("/login")
  2.     public String openWeChatLogin(HttpServletRequest httpServletRequest) {
  3.         // 防止csrf攻击(跨站请求伪造攻击)
  4.         String state = UUID.randomUUID().toString().replaceAll( "-", "");
  5.         // 采用redis等进行缓存state 使用sessionId为key 30分钟后过时,可配置
  6.         RedisPoolUtil.setEx( "wechat-open-state-" + httpServletRequest.getSession().getId(), state, Integer.parseInt(env.getProperty("wechat.open.exTime", "1800")));
  7.         String url = "https://open.weixin.qq.com/connect/qrconnect?" +
  8.                 "appid=" +
  9.                 env.getProperty( "wechat.open.pc.appid").trim() +
  10.                 "&redirect_uri=" +
  11.                 env.getProperty( "application.url") +
  12.                 env.getProperty( "wechat.open.pc.redirect_uri").trim() +
  13.                  "&response_type=code" +
  14.                 "&scope=snsapi_login" +
  15.                 "&state=" +
  16.                 state +     // 由后台自动生成
  17.                  "#wechat_redirect";
  18.         return "redirect:" + url;
  19.     }

2)用户赞成受权与否

用户容许受权后,将会重定向到redirect_uri的网址上,而且带上code和state参数

redirect_uri?code=CODE&state=STATE

若用户禁止受权,则不会重定向到咱们提供的回调地址中

 

成功受权后,将得到Code,经过Code能够获取access_token

 

3)获取access_token

经过上述方法获取的code获取access_token.

Http Get请求

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,                      // access_token接口调用凭证超时时间,单位(秒)
"refresh_token":"REFRESH_TOKEN",       //用户刷新access_token
"openid":"OPENID",                                  //受权用户惟一标识
"scope":"SCOPE",                                     //用户受权的做用域,使用逗号(,)分隔
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"  //当且仅当该网站应用已得到该用户的userinfo受权时,才会出现该字段
}

失败返回的样例:

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

失败可能缘由:  暂时不明

  1.     @RequestMapping( "/callback/pc")
  2.     public String openWeChatCallback(HttpServletRequest httpServletRequest, Model model) {
  3.         String code = httpServletRequest.getParameter("code");
  4.         String state = httpServletRequest.getParameter("state");
  5.         String url = null;
  6.         // 判断state是否合法
  7.         String stateStr = RedisPoolUtil.get("wechat-open-state-" + httpServletRequest.getSession().getId());
  8.         if (StringUtils.isEmpty(code) || StringUtils.isEmpty(stateStr) || !state.equals(stateStr)) {
  9.             throw new WechatParamException("非法参数,请从新登录", "/");
  10.         }
  11.         url = "https://api.weixin.qq.com/sns/oauth2/access_token?" +
  12.                 "appid=" +
  13.                 env.getProperty( "wechat.open.pc.appid").trim() +
  14.                 "&secret=" +
  15.                 env.getProperty( "wechat.open.pc.appsecret").trim() +
  16.                 "&code=" +
  17.                 code +
  18.                 "&grant_type=authorization_code";
  19.         JSONObject wechatAccessToken = HttpClientUtils.httpGet(url);
  20.         if (wechatAccessToken.get("errcode") != null) {
  21.             throw new WechatParamException("获取accessToken失败", "/wechat/open/login");
  22.         }
  23.         String accessToken = (String) wechatAccessToken.get("access_token");
  24.         String openid = (String) wechatAccessToken.get("openid");
  25.         String unionid = (String) wechatAccessToken.get("unionid");
  26.         if (StringUtils.isEmpty(accessToken) || StringUtils.isEmpty(openid) || StringUtils.isEmpty(unionid)) {
  27.             throw new WechatParamException("获取accessToken失败", "/wechat/open/login");
  28.         }
  29.         // TODO:根据Openid或Unionid对数据库进行查询,若是查询到对应的用户数据,则不须要再向微信服务器发送请求去返回数据。
  30.         // TODO: 建议使用Unionid做为查询条件。
  31.         WeChatUserInfo weChatUserInfo = null;
  32.         wechatAccessToken = null;  // FIXME: 这里应该是从数据库中查询获取用户信息逻辑。
  33.         if (wechatAccessToken == null) {
  34.             // 新用户
  35.             weChatUserInfo = getUserInfoByAccessToken(accessToken);
  36.             // 数据库插入的操做
  37.         }
  38.         if (weChatUserInfo != null) {
  39.             model.addAttribute(weChatUserInfo);
  40.             return "wechatUser";
  41.         }
  42.         throw new WechatParamException("获取用户信息失败", "/wechat/open/login");
  43.     }

4)经过access_token调用接口获取用户我的信息(UnionID机制)

前提:

1. access_token有效且未超时;

2. 微信用户已受权给第三方应用账号相应接口做用域(scope)。

Http Get请求:

https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID

参数

是否必须

说明

access_token

调用凭证

openid

普通用户的标识,对当前开发者账号惟一

lang

国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语,默认为zh-CN

 

返回成功的json结果(样例):

{
"openid":"OPENID",        //普通用户的标识,对当前开发者账号惟一
"nickname":"NICKNAME",   //普通用户昵称
"sex":1,                                //普通用户性别,1为男性,2为女性
"province":"PROVINCE",      //普通用户我的资料填写的省份
"city":"CITY",                        //普通用户我的资料填写的城市
"country":"COUNTRY",         //国家,如中国为CN
"headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",       //用户头像,最后一个数值表明正方形头像大小(有0、4六、6四、9六、132数值可选,0表明640*640正方形头像),用户没有头像时该项为空
"privilege":[   //用户特权信息,json数组,如微信沃卡用户为(chinaunicom)
"PRIVILEGE1",
"PRIVILEGE2"
],
"unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"   //用户统一标识。针对一个微信开放平台账号下的应用,同一用户的unionid是惟一的
}

 

失败JSON样例:

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

 

注意:在用户修改微信头像后,旧的微信头像URL将会失效,所以开发者应该本身在获取用户信息后,将头像图片保存下来,避免微信头像URL失效后的异常状况

最好保存用户unionID信息,以便之后在不一样应用中进行用户信息互通。

  1. private WeChatUserInfo getUserInfoByAccessToken( String accessToken) {
  2.         if (StringUtils.isEmpty(accessToken)) {
  3.             return null;  //"accessToken为空";
  4.         }
  5.         String get_userInfo_url = null;
  6.         get_userInfo_url = "https://api.weixin.qq.com/sns/userinfo?" +
  7.                 "access_token=" +
  8.                 accessToken +
  9.                 "&openid=" +
  10.                 env.getProperty( "wechat.open.pc.appid").trim();
  11.         String userInfo_result = HttpClientUtils.httpGet(get_userInfo_url, "utf-8");
  12.         if (!userInfo_result.equals("errcode")) {
  13.             WeChatUserInfo weChatUserInfo = JSON.parseObject(userInfo_result, new TypeReference<WeChatUserInfo>() {
  14.             });
  15.             // TODO: 须要把头像信息下载到文件服务器,而后替换掉头像URL。微信的或许不可靠,假设微信用户更换了头像,旧头像URL是否会保存?而这个URL信息却存放在咱们的数据库中,不可靠
  16.             return weChatUserInfo;
  17.         }
  18.         return null;  //"获取用户信息失败"
  19.     }

5)刷新access_token

因为access_token有效期(目前为2个小时)较短,当access_token超时后,可使用refresh_token进行刷新,access_token刷新结果有两种:

1. 若access_token已超时,那么进行refresh_token会获取一个新的access_token,新的超时时间;
2. 若access_token未超时,那么进行refresh_token不会改变access_token,但超时时间会刷新,至关于续期access_token。

refresh_token拥有较长的有效期(30天),当refresh_token失效的后,须要用户从新受权。

 

请求方法:

获取第一步的code后,请求如下连接进行refresh_token:

https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN

参数说明:

参数

是否必须

说明

appid

应用惟一标识

grant_type

填refresh_token

refresh_token

填写经过access_token获取到的refresh_token参数

 

成功返回的结果:

{
"access_token":"ACCESS_TOKEN",    //接口调用凭证
"expires_in":7200,                             // access_token接口调用凭证超时时间,单位(秒)
"refresh_token":"REFRESH_TOKEN",   //用户刷新access_token
"openid":"OPENID",                          //受权用户惟一标识
"scope":"SCOPE"                              //用户受权的做用域,使用逗号(,)分隔
}

失败样例:

{"errcode":40030,"errmsg":"invalid refresh_token"}

 

注意:

一、Appsecret 是应用接口使用密钥,泄漏后将可能致使应用数据泄漏、应用的用户数据泄漏等高风险后果;存储在客户端,极有可能被恶意窃取(如反编译获取Appsecret);
二、access_token 为用户受权第三方应用发起接口调用的凭证(至关于用户登陆态),存储在客户端,可能出现恶意获取access_token 后致使的用户数据泄漏、用户微信相关接口功能被恶意发起等行为;
三、refresh_token 为用户受权第三方应用的长效凭证,仅用于刷新access_token,但泄漏后至关于access_token 泄漏,风险同上。

建议将secret、用户数据(如access_token)放在App云端服务器,由云端中转接口调用请求。

 

5、测试结果

一、网站应用

首先开启redis。而后运行代码。因为SpringBoot会使用内置的Tomcat容器进行管理,直接运行就能够了,而后点击微信登陆。弹出扫码登陆窗口,手机扫码赞成登陆后就能够获取到用户信息了.

 

6、应用关键参数位置

APPID和APPSecret以及回调地址位置,注:须要修改受权回调域,即回调地址

 

 

微信开放平台开发第三方受权登录(一):开发前期准备
[Wēixìn kāifàng píngtái kāifā dì sānfāng shòuquán dēnglù (yī): Kāifā qiánqí zhǔnbèi]
WeChat open platform for third-party developers authorized landing (a): the development preparatory
相关文章
相关标签/搜索