Java微信公众平台开发之OAuth2.0网页授权

根据官方文档点击查看在微信公众号请求用户网页授权之前,开发者需要先到公众平台官网中的“开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项中,修改授权回调域名。请注意,这里填写的是域名(是一个字符串),而不是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;
}
时间: 2024-08-07 00:15:50

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

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

1.首先在某微信平台下配置OAuth2.0授权回调页面: 2.通过appid构造url获取微信回传code值(appid可在微信平台下找到) 1).微信不弹出授权页面url: A.code回传到页面wxProcess2.aspx,不带参数 [csharp] view plain copy Response.Redirect("https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + appid + "&

微信公众平台开发(二)网页授权

微信公众平台OAuth2.0授权详细步骤如下: 1. 用户关注微信公众账号.2. 微信公众账号提供用户请求授权页面URL.3. 用户点击授权页面URL,将向服务器发起请求4. 服务器询问用户是否同意授权给微信公众账号(scope为snsapi_base时无此步骤)5. 用户同意(scope为snsapi_base时无此步骤)6. 服务器将CODE通过回调传给微信公众账号7. 微信公众账号获得CODE8. 微信公众账号通过CODE向服务器请求Access Token9. 服务器返回Access T

记微信公众平台开发之V3版微信native原生支付功能开发

一.生成商品信息 动态链接支付过程中,是先生成商品交易进行,再来进行支付交易的. 1. 商品信息准备 主要是先定义商品的名称及价格,以及交易号.代码如下. include_once("../WxPayPubHelper/WxPayPubHelper.php"); //使用统一支付接口 $unifiedOrder = new UnifiedOrder_pub(); //设置统一支付接口参数 //设置必填参数 //appid已填,商户无需重复填写 //mch_id已填,商户无需重复填写 /

微信公众平台开发之emoji表情的使用

关于表情的各种符号代码,参照柳老师的博客:http://blog.csdn.net/lyq8479/article/details/9229631 这里只介绍简单的使用方法. 我们以一个微笑的表情来看,它的表达式有三种: [微笑] 2. /微笑 3. /::) 在CoreService核心类中加入代码测试: public class CoreService {    public static String processRequest(Map<String, String> requestM

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

本篇文章你将学到:在自己做的微信网站里,利用oauth2.0网页授权接口获取用户的信息(openid,姓名,性别,地区,头像等).如大转盘等游戏记录哪个微信用户获得什么奖品.H5等小游戏需要把分数与对应用户捆绑在一起等网页应用. 微信公众平台oauth2.0网页授权能干什么 它是在自己做的网站中不用用户登录来获取微信用户相关信息的,进而实现相关业务. 说明与注意 1.网页授权分为两种, 一种为只获取openid  (基本授权 snsapi_base) 一种为获取用户全部信息 (高级授权 snsa

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

本文介绍如何获得微信公众平台关注用户的基本信息,包括昵称.头像.性别.国家.省份.城市.语言.本文的方法将囊括订阅号和服务号以及自定义菜单各种场景,无论是否有高级接口权限,都有办法来获得用户基本信息,而无需模拟登录. 在本文中,特别要注意的是有两个不同的Access Token,他们产生的方式不一样,一种是使用AppID和AppSecret获取的access_token,一种是OAuth2.0授权中产生的access_token,方倍工作室分别称为全局Access Token和授权Access

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

微信公众平台开发 OAuth2.0网页授权认证 网页授权获取用户基本信息 作者:方倍工作室 微信公众平台最近新推出微信认证,认证后可以获得高级接口权限,其中一个是OAuth2.0网页授权,很多朋友在使用这个的时候失败了或者无法理解其内容,希望我出个教程详细讲解一下,于是便有了这篇文章. 一.什么是OAuth2.0 官方网站:http://oauth.net/   http://oauth.net/2/ 权威定义:OAuth is An open protocol to allow secure

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

微信公众平台开发 OAuth2.0网页授权认证 网页授权获取用户基本信息 作者:方倍工作室 微信公众平台最近新推出微信认证,认证后可以获得高级接口权限,其中一个是OAuth2.0网页授权,很多朋友在使用这个的时候失败了或者无法理解其内容,希望我出个教程详细讲解一下,于是便有了这篇文章. 一.什么是OAuth2.0 官方网站:http://oauth.net/   http://oauth.net/2/ 权威定义:OAuth is An open protocol to allow secure

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

一.准备阶段 需要准备事项: 1.一个能在公网上访问的项目: 见:[  Java微信公众平台开发_01_本地服务器映射外网  ] 2.一个微信公众平台账号: 去注册:(https://mp.weixin.qq.com/) 3.策略文件 见:[ Java企业微信开发_Exception_02_java.security.InvalidKeyException: Illegal key size ] 4.微信官方消息加解密工具包 需要下载微信官方的消息加解密的工具包,主要是AES加密工具 下载地址: