根据官方文档在微信公众号请求用户网页授权之前,开发者需要先到公众平台官网中的“开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项中,修改授权回调域名。请注意,这里填写的是域名(是一个字符串),而不是URL,因此请勿加 http:// 等协议头,也不需要加具体的项目名,在域名空间的根目录放一个txt文件才能验证通过

一、两种scope授权方式

  • 以snsapi_base为scope发起的网页授权,是用来获取进入页面的用户的openid的,并且是静默授权并自动跳转到回调页的。用户感知的就是直接进入了回调页(往往是业务页面)
  • 以snsapi_userinfo为scope发起的网页授权,是用来获取用户的基本信息的。但这种授权需要用户手动同意,并且由于用户同意过,所以无须关注,就可在授权后获取该用户的基本信息

二、关于特殊场景下的静默授权

  • 上面已经提到,对于以snsapi_base为scope的网页授权,就静默授权的,用户无感知
  • 对于已关注公众号的用户,如果用户从公众号的会话或者自定义菜单进入本公众号的网页授权页,即使是scope为snsapi_userinfo,也是静默授权,用户无感知

三、用户同意授权,获取code

请求链接https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect 
package com.phil.wechatauth.model.req;

import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import java.util.TreeMap; import com.phil.common.config.SystemConfig;
import com.phil.common.params.AbstractParams;
import com.phil.common.util.HttpReqUtil; /**
* 获取授权code请求参数
*
* @author phil
* @date 2017年7月2日
*
*/
public class AuthCodeParams extends AbstractParams implements Serializable{ /**
*
*/
private static final long serialVersionUID = 1L; public static final String SCOPE_SNSAPIBASE = "snsapi_base"; // snsapi_base(不需要弹出授权页面,只能获取openid)
public static final String SCOPE_SNSPAIUSERINFO = "snsapi_userinfo"; // 弹出授权页面(获取用户基本信息)
private String appid;
private String redirect_uri; // 使用urlencode对链接进行处理
private String response_type = "code";
private String scope;
private String state; public AuthCodeParams() {
super();
} public AuthCodeParams(String appid, String redirect_uri, String response_type, String scope, String state) {
super();
this.appid = appid;
this.redirect_uri = redirect_uri;
this.response_type = response_type;
this.scope = scope;
this.state = state;
} /**
* 参数组装
*
* @return
*/
public Map<String, String> getParams() throws UnsupportedEncodingException {
Map<String, String> params = new TreeMap<String, String>();
params.put("appid", this.appid);
params.put("redirect_uri", HttpReqUtil.urlEncode(this.redirect_uri, SystemConfig.CHARACTER_ENCODING));
params.put("response_type", this.response_type);
params.put("scope", this.scope);
params.put("state", this.state);
return params;
} public String getAppid() {
return appid;
} public void setAppid(String appid) {
this.appid = appid;
} public String getRedirect_uri() {
return redirect_uri;
} public void setRedirect_uri(String redirect_uri) {
this.redirect_uri = redirect_uri;
} public String getResponse_type() {
return response_type;
} public String getScope() {
return scope;
} public void setScope(String scope) {
this.scope = scope;
} public String getState() {
return state;
} public void setState(String state) {
this.state = state;
}
}
组装请求链接
/**
* 获取授权请求path
* @param basic
* @param path
* @return
* @throws Exception
*/
public String getAuthPath(AbstractParams basic, String path) throws Exception{
Map<String,String> params = basic.getParams();
path = HttpRequestUtil.setParmas(params, path,"")+"#wechat_redirect";
return path;
}
 
尤其注意:由于授权操作安全等级较高,所以在发起授权请求时,微信会对授权链接做正则强匹配校验,如果链接的参数顺序不对,授权页面将无法正常访问
请在微信客户端中打开此链接
如果用户同意授权,页面将跳转至redirect_uricode=CODE&state=STATE ,可以用request.getParameter("code")直接获取到code,在此之后检验state是否发生变化。code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期,可用redis、mc等缓存 

四、通过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获取用户信息等步骤,也必须从服务器发起。

请求参数封装

package com.phil.wechatauth.model.req;

import java.io.Serializable;
import java.util.Map;
import java.util.TreeMap; import com.phil.common.params.AbstractParams; /**
* 获取授权请求token的请求参数
* @author phil
* @date 2017年7月2日
*
*/
public class AuthTokenParams extends AbstractParams implements Serializable{
/**
*
*/
private static final long serialVersionUID = 4652953400751046159L; private String appid; //公众号的唯一标识
private String secret; //公众号的appsecret
private String code; //填写第一步获取的code参数
private String grant_type = "authorization_code"; public AuthTokenParams() {
super();
} public AuthTokenParams(String appid, String secret, String code, String grant_type) {
super();
this.appid = appid;
this.secret = secret;
this.code = code;
this.grant_type = grant_type;
} /**
* 参数组装
* @return
*/
public Map<String, String> getParams() {
Map<String, String> params = new TreeMap<String, String>();
params.put("appid", this.appid);
params.put("secret", this.secret);
params.put("code", this.code);
params.put("grant_type", this.grant_type);
return params;
} public String getAppid() {
return appid;
} public void setAppid(String appid) {
this.appid = appid;
} public String getSecret() {
return secret;
} public void setSecret(String secret) {
this.secret = secret;
} public String getCode() {
return code;
} public void setCode(String code) {
this.code = code;
} public String getGrant_type() {
return grant_type;
}
}

返回的json封装

package com.phil.wechatauth.model.resp;

/**
* 网页授权access_token
*
* @author phil
* @date 2017年7月2日
*
*/
public class AuthAccessToken extends AccessToken { private String refresh_token; // 用户刷新access_token
private String openid; // 用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenID
private String scope; // 用户授权的作用域,使用逗号(,)分隔 public String getRefresh_token() {
return refresh_token;
} public void setRefresh_token(String refresh_token) {
this.refresh_token = refresh_token;
} public String getOpenid() {
return openid;
} public void setOpenid(String openid) {
this.openid = openid;
} public String getScope() {
return scope;
} public void setScope(String scope) {
this.scope = scope;
} }

获取access_token方法

	/**
* 获取网页授权凭证
* @param basic
* @param path
* @return
*/
public AuthAccessToken getAuthAccessToken(AbstractParams basic, String path) {
AuthAccessToken authAccessToken = null;
//获取网页授权凭证
try {
String result = HttpReqUtil.HttpsDefaultExecute(HttpReqUtil.GET_METHOD, path, basic.getParams(), null); if(result != null){
authAccessToken = JsonUtil.fromJson(result, AuthAccessToken.class);
}
} catch (Exception e) {
authAccessToken = null;
logger.info("error"+e.getMessage());
}
return authAccessToken;
}

获取授权进入页面

// 获取token的链接
private final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token"; @RequestMapping(value = "bindWxPhone", method = { RequestMethod.GET })
public String prize(HttpServletRequest request, HttpServletResponse response, String url) throws Exception {
AuthAccessToken authAccessToken = null;
// 用户同意授权后可以获得code,检验state
String code = request.getParameter("code");
if(code==null){
return null;
}
String state = request.getParameter("state");
if(state.equals(MD5Util.MD5Encode("ceshi", ""))){
AuthTokenParams authTokenParams = new AuthTokenParams();
authTokenParams.setAppid("");
authTokenParams.setSecret("");
authTokenParams.setCode(code);
authAccessToken = oAuthService.getAuthAccessToken(authTokenParams, ACCESS_TOKEN_URL);
}
if(authAccessToken!=null){
logger.info("网页授权的accessToken=" + authAccessToken.getAccess_token());
logger.info("正在绑定的openid=" + authAccessToken.getOpenid());
}
return "/system/wxuserprize/bindPhone";
}

五、刷新access_token(如果需要)

由于access_token拥有较短的有效期,当access_token超时后,可以使用refresh_token进行刷新,refresh_token有效期为30天,当refresh_token失效之后,需要用户重新授权。

请求参数封装

package com.phil.wechatauth.model.req;

import java.io.Serializable;
import java.util.Map;
import java.util.TreeMap; import com.phil.common.params.AbstractParams; /**
* 刷新token请求
* @author phil
* @date 2017年7月2日
*
*/
public class RefreshTokenParams extends AbstractParams implements Serializable{
/**
*
*/
private static final long serialVersionUID = -7200815808171378571L; private String appid;
private String grant_type = "refresh_token";
private String refresh_token; public RefreshTokenParams(String appid, String grant_type, String refresh_token) {
super();
this.appid = appid;
this.grant_type = grant_type;
this.refresh_token = refresh_token;
} /**
* 参数组装
*
* @return
*/
public Map<String, String> getParams() {
Map<String, String> params = new TreeMap<String, String>();
params.put("appid", this.appid);
params.put("grant_type", this.grant_type);
params.put("refresh_token", this.refresh_token);
return params;
} public String getAppid() {
return appid;
} public void setAppid(String appid) {
this.appid = appid;
} public String getGrant_type() {
return grant_type;
} public String getRefresh_token() {
return refresh_token;
} public void setRefresh_token(String refresh_token) {
this.refresh_token = refresh_token;
}
}
	/**
* 刷新网页授权验证
* @param basic 参数
* @param path 请求路径
* @return
*/
public String refreshAuthAccessToken(AbstractParams basic, String path) {
AuthAccessToken authAccessToken = null;
//刷新网页授权凭证
try {
String result = HttpReqUtil.HttpsDefaultExecute(HttpReqUtil.GET_METHOD, path, basic.getParams(), null);
if(result != null){
authAccessToken = JsonUtil.fromJson(result, AuthAccessToken.class);
}
} catch (Exception e) {
authAccessToken = null;
logger.info("error"+e.getMessage()); }
return authAccessToken==null?null:authAccessToken.getAccess_token();
}

六、拉取用户信息

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

通过网页授权获取的用户信息

/**
* 通过网页授权获取的用户信息
*
* @author phil
*/
public class AuthUserInfo {
// 用户标识
private String openid;
// 用户昵称
private String nickname;
// 性别(1是男性,2是女性,0是未知)
private String sex;
// 国家
private String country;
// 省份
private String province;
// 城市
private String city;
// 用户头像链接
private String headimgurl;
// 用户特权信息
private List<String> privilege;
// 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段
private String unionid; public String getOpenid() {
return openid;
} public void setOpenid(String openid) {
this.openid = openid;
} public String getNickname() {
return nickname;
} public void setNickname(String nickname) {
this.nickname = nickname;
} public String getSex() {
return sex;
} public void setSex(String sex) {
this.sex = sex;
} public String getCountry() {
return country;
} public void setCountry(String country) {
this.country = country;
} public String getProvince() {
return province;
} public void setProvince(String province) {
this.province = province;
} public String getCity() {
return city;
} public void setCity(String city) {
this.city = city;
} public String getHeadimgurl() {
return headimgurl;
} public void setHeadimgurl(String headimgurl) {
this.headimgurl = headimgurl;
} public List<String> getPrivilege() {
return privilege;
} public void setPrivilege(List<String> privilege) {
this.privilege = privilege;
} public String getUnionid() {
return unionid;
} public void setUnionid(String unionid) {
this.unionid = unionid;
}
}

获取方法

//获取授权用户信息
private final String USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo";
/**
* 通过网页授权获取用户信息
* @param accessToken
* @param openid
* @return
*/
public AuthUserInfo getAuthUserInfo(String accessToken, String openid) {
AuthUserInfo authUserInfo = null;
//通过网页授权获取用户信息
Map<String, String> params = new TreeMap<String, String>();
params.put("openid", openid);
params.put("access_token", accessToken);
String result = HttpReqUtil.HttpsDefaultExecute(HttpReqtUtil.GET_METHOD, USERINFO_URL, params, null);
if(null != result){
try {
authUserInfo = JsonUtil.fromJson(result, AuthUserInfo.class);
} catch (JsonSyntaxException e) {
logger.info("transfer exception");
}
}
return authUserInfo;
}

七、检验授权凭证(access_token)是否有效

//判断用户accessToken是否有效
private final String AUTH_URL = "https://api.weixin.qq.com/sns/auth"; /**
* 检验授权凭证(access_token)是否有效
* @param accessToken 网页授权接口调用凭证
* @param openid 用户的唯一标识
* @return { "errcode":0,"errmsg":"ok"}表示成功 { "errcode":40003,"errmsg":"invalid openid"}失败
*/
public ResultState authToken(String accessToken,String openid){
ResultState state = null;
Map<String,String> params = new TreeMap<String,String>();
params.put("access_token",accessToken);
params.put("openid", openid);
String json = HttpReqUtil.HttpsDefaultExecute(HttpReqUtil.GET_METHOD, AUTH_URL, params,"");
if(json!=null){
state = JsonUtil.fromJson(json, ResultState.class);
}
return state;
}

Java微信公众平台开发之OAuth2.0网页授权的更多相关文章

  1. 微信公众平台开发—利用OAuth2.0获取微信用户基本信息

    在借鉴前两篇获取微信用户基本信息的基础下,本人也总结整理了一些个人笔记:如何通过OAuth2.0获取微信用户信息 1.首先在某微信平台下配置OAuth2.0授权回调页面: 2.通过appid构造url ...

  2. 微信公众平台开发(71)OAuth2.0网页授权

    微信公众平台开发 OAuth2.0网页授权认证 网页授权获取用户基本信息 作者:方倍工作室 微信公众平台最近新推出微信认证,认证后可以获得高级接口权限,其中一个是OAuth2.0网页授权,很多朋友在使 ...

  3. ***微信公众平台开发: 获取用户基本信息+OAuth2.0网页授权

    本文介绍如何获得微信公众平台关注用户的基本信息,包括昵称.头像.性别.国家.省份.城市.语言.本文的方法将囊括订阅号和服务号以及自定义菜单各种场景,无论是否有高级接口权限,都有办法来获得用户基本信息, ...

  4. 微信公众平台开发-OAuth2.0网页授权(含源码)

    微信公众平台开发-OAuth2.0网页授权接口.网页授权接口详解(含源码)作者: 孟祥磊-<微信公众平台开发实例教程> 在微信开发的高级应用中,几乎都会使用到该接口,因为通过该接口,可以获 ...

  5. 黄聪:微信公众平台开发OAuth2.0网页授权(转)

    微信公众平台开发 OAuth2.0网页授权认证 网页授权获取用户基本信息 作者:方倍工作室 微信公众平台最近新推出微信认证,认证后可以获得高级接口权限,其中一个是OAuth2.0网页授权,很多朋友在使 ...

  6. 微信公众平台OAuth2.0网页授权

    微信公众平台最近新推出微信认证,认证后可以获得高级接口权限,其中一个是OAuth2.0网页授权,很多朋友在使用这个的时候失败了或者无法理解其内容,希望我出个教程详细讲解一下,于是便有了这篇文章. 一. ...

  7. 微信公众平台开发(71)OAuth2.0网页授权-摘抄

      微信公众平台开发 OAuth2.0网页授权认证 网页授权获取用户基本信息 作者:方倍工作室 微信公众平台最近新推出微信认证,认证后可以获得高级接口权限,其中一个是OAuth2.0网页授权,很多朋友 ...

  8. Java微信公众平台开发_02_启用服务器配置

    源码将在晚上上传到 github 一.准备阶段 需要准备事项: 1.一个能在公网上访问的项目: 见:[  Java微信公众平台开发_01_本地服务器映射外网  ] 2.一个微信公众平台账号: 去注册: ...

  9. 微信公众号开发之VS远程调试

    目录 (一)微信公众号开发之VS远程调试 (二)微信公众号开发之基础梳理 (三)微信公众号开发之自动消息回复和自定义菜单 前言 微信公众平台消息接口的工作原理大概可以这样理解:从用户端到公众号端一个流 ...

随机推荐

  1. 【LeetCode】110. Balanced Binary Tree

    题目: Given a binary tree, determine if it is height-balanced. For this problem, a height-balanced bin ...

  2. 【Android Developers Training】 40. 序言:通过NFC共享文件

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  3. 遇到looper之类关于消息循环的

    原因大概是因为无法创建消息循环,这时候要考虑函数是否要在主线程或者不在主线程中进行,改一下即可

  4. 2.如何实现使用VBS脚本程序对直播间自动评论

    前言:本文使用的是VBS脚本,实现了对繁星直播自动登录,自动进入房间并且自动评论. 前提准备:把需要刷的评论放到mysql中,再使用vbs读出评论 -------------------------- ...

  5. 如何简单的实现新手引导之UGUI篇

    一个完整的游戏项目肯定是要做新手引导的,而引导做的好坏可能会影响玩家的留存.那么怎么简单的实现个简有效的引导呢!先不说废话,先看看效果,这是一个基于UGUI做的一个简单的引导! 怎么样,看着是那么回事 ...

  6. CentOS6.4虚拟机设置固定IP、安装JDK、Tomcat、Redis并部署web项目

    一.CentOS设置固定IP 1.直接修改配置文件的方式,原文地址:http://www.cnblogs.com/zhja/p/3964159.html (1)首先获取你的GATEWAY 方便后面在c ...

  7. mvcSSHweb.xml要配置的信息

    <?xml version="1.0" encoding="UTF-8"?><web-app version="3.0" ...

  8. JavaSE中Map框架学习笔记

    前言:最近几天都在生病,退烧之后身体虚弱.头疼.在床上躺了几天,什么事情都干不了.接下来这段时间,要好好加快进度才好. 前面用了三篇文章的篇幅学习了Collection框架的相关内容,而Map框架相对 ...

  9. ASP.NET 平台下的MVC框架

    这段时间在学习MVC框架,希望自己的一点心得能够帮助正在学习的同仁. 在阅读一些大牛的博客的时候看到一句话,感觉特别好,“你应该尝试MVC,是因为最终你会学到一些东西,它可以使你成为更好的Web开发人 ...

  10. 2017年1月1日 App Store中的所有应用都必须启用 App Transport Security安全功能

    2017年1月1日 App Store中的所有应用都必须启用 App Transport Security安全功能,否则极有可能被拒! 在WWDC 2016开发者大会上,苹果宣布了一个最后期限:到20 ...