码迷,mamicode.com
首页 > 微信 > 详细

微信公众号之订阅号(已认证)实现oauth2授权登录详细步骤介绍

时间:2016-04-22 19:01:51      阅读:8340      评论:0      收藏:0      [点我收藏+]

标签:

一: 简介

通过 微信公众平台---->权限接口 可以得知 微信的订阅号是没有授权登录接口的,只有服务号才有该权限。这点微信公众平台在多处反复强调

技术分享

最终的事实是:微信订阅号是可以实现授权登录的!


二:具体实现步骤:

  1. 首先在 微信公众平台(https://mp.weixin.qq.com/) 【开发】----> 【基本配置】----->【服务器配置】完成基本的配置信息

URL: 这里的地址我写的是我们HTML5项目的某个Controller或Servlet的地址,例如 http://www.example.com/weixin/checkSignature.do

          注意这个CheckSignatureController中是要写代码的,代码的业务逻辑是要验证签名并返回echostr字段;还需要注意www.example.com 这个地址必须是外网地址(内网不行的), 因为当你配置完所有的基本信息时,当提交的时候,微信公众平台会回答你刚才填的URL地址即http://www.example.com/weixin/checkSignature.do, 如果你填内网的地址,那么这个URL调不到,如果签名验证不过去,这个基本配置就配置不成功。当你写好这个CheckSignatureController后,还要将代码放到测试环境中去,以便微信公众平台可以回调你这个Controller

@Controller
@RequestMapping(value="/weixin")
public class CheckSignatureController extends BaseController {
	
	private static transient final Logger log = LoggerFactory.getLogger(CheckSignatureController.class);
	public static String WEIXIN_TOKEN = "Token";
	
	
	@RequestMapping(value ="checkSignature.do", produces = "application/json; charset=utf-8")
	@ResponseBody
	public String checkSignature(HttpServletRequest request) {    
		String echostr = request.getParameter("echostr");		// 随机字符串
		
		if (isSignature(request)) {
		    return echostr;
		}
			
		return null;
	}
	
	
	// 检查签名
	public boolean isSignature(HttpServletRequest request) {
	    String signature = request.getParameter("signature");			// 微信加密签名
	    String timestamp = request.getParameter("timestamp");			// 时间戳
	    String nonce = request.getParameter("nonce");				// 随机数
			
	    String[] arr = new String[] {timestamp, nonce, WEIXIN_TOKEN};
	    Arrays.sort(arr);
	    String s = arr[0] + arr[1] + arr[2];
	    MessageDigest md;
	    byte[] digest = null;
	    try {
		md = MessageDigest.getInstance("SHA-1");
		digest = md.digest(s.getBytes("utf-8"));
	    } catch (Exception e) {
		e.printStackTrace();
	    }
	   
	    String sign = bytesToHexString(digest);
	    return signature.equals(sign);
	}
	
	
	public static final String bytesToHexString(byte[] bArray) {  
		StringBuffer sb = new StringBuffer(bArray.length);  
		String sTemp;  
		for (int i = 0; i < bArray.length; i++) {  
		    sTemp = Integer.toHexString(0xFF & bArray[i]);  
		    if (sTemp.length() < 2)  
			sb.append(0);  
		    sb.append(sTemp.toUpperCase());  
		}  
		return sb.toString().toLowerCase();  
	}  	
}


当你点击基本信息的【提交】按钮时,微信公众平台会向你项目发送http请求:

http://www.example.com/weixin/checkSignature.do?signature=d96625be6855baa013e6c66cb9155dd38ed8deb5&echostr=8312595572152199567&timestamp=1460511115&nonce=534926942

如果这个地址能返回http请求中的echostr参数,就能提交成功,否则提交还会提示报错

Token:是一个字符串,自己随意写,但是要保证一点CheckSignatureController中会用到Token这个值,两者要保证完全一致即可

EncodingAESKey: 我选择的是随机生成的

2: 测试号管理

登录这个地址,进行配置:http://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index

在这个地址中要配置完所有信息

接口配置信息

URL: http://www.example.com/weixin/checkSignature.do 和基本信息配置一样
Token:和基本配置中的token保持一致

JS接口安全域名

 域名:http://www.example.com  

体验接口权限表

    技术分享

    点击修改,然后 填入: www.example.com  , 注意不要带http


三:配置自动回复

技术分享

填入:<a href="https://open.weixin.qq.com/connect/oauth2/authorize?appid=微信开放平台(网站应用)AppID&redirect_uri=http://www.example.com/oauth2.do&response_type=code&scope=snsapi_login&state=1#wechat_redirect">点击这里立即体验</a>

然后保存

注意:href里面的值大部分是固定的,特别注意appid参数,如果这个值错了,你就不能完成授权登录

appid:为微信开放平台(网站应用,一定要是是网站应用,不能是移动应用)中的AppID(https://open.weixin.qq.com 这个地址中的appid),更不要写微信公众平台中的AppID

scope:参数值为snsapi_login,不要写snsapi_base和snsapi_userinfo

redirect_uri:这个值写HTML5项目中的一个Controller的映射地址,当用户点击立即体验超链接的时候,会跳转到授权登录页面,当点击授权登录之后微信公众平台会回调这个地址,并在这个地址上追加code和state参数值

http://www.example.com/oauth2.do?code=0419p3Cc0YxTtG1nadCc0Ms7Cc09p3C8&state=1

你需要获取code参数,从而调用微信公众平台的其他API,进而拿到微信用户的基本信息,如昵称,头像,性别等

这两个参数非常关键,我在开发中就因为这两个值没写对,卡了好长时间

http://www.example.com/oauth2.do 代码逻辑

1. 微信公众平台回调你的地址:http://www.example.com/oauth2.do?code=0419p3Cc0YxTtG1nadCc0Ms7Cc09p3C8&state=1

2. 获取code参数,调用微信公众平台access_token接口,来获取access_token值

3.根据上步获取的access_token值,调用userinfo接口来获取用户的基本信息


具体代码如下:

@Controller
public class Oauth2Controller extends BaseController {
	private static transient final Logger log = LoggerFactory.getLogger(Oauth2Controller.class);
	static String AppID = "微信开放平台的网站应用(不能是移动应用)https://open.weixin.qq.com (更不是公众平台切记)AppID";
	static String AppSecret = "微信开放平台Secret";
	static String State = "1"; 
	
	@RequestMapping(value ="/oauth2.do", produces = "application/json; charset=utf-8")
	@ResponseBody
	public String mp(HttpServletRequest request) {    
		// 1. 获取code ----------------------------------------------------
		String CODE = request.getParameter("code");
		String state = request.getParameter("state");
		if (!State.equals(state)) {
			return null;
		}
		
		JsonMapper json = JsonMapper.nonDefaultMapper();
		AccessTokenHelper accessTokenHelper = AccessTokenHelper.getInstance();
		AccessToken accessToken = accessTokenHelper.getAccessToken();
		if (accessToken != null) {
			Date expireEndDate = accessTokenHelper.getExpireInDate();
			if (new Date().getTime() >= expireEndDate.getTime() ) {
				// 2.accessToken过期了,需要重新获取 使用code换取access_token--------
				accessToken = requestAccessToken(CODE, json);
			}
		} else {
			accessToken = requestAccessToken(CODE, json);
		}
		
		
		String accessTokenStr = accessToken.getAccess_token();
		String openid = accessToken.getOpenid();
		log.info("--accessToken: " + accessToken);
		
		// 3.使用access_token获取用户信息-------------------------------
		// https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
		Map<String, Object> paramMap = new HashMap<String, Object>();
		String userinfoURL = "https://api.weixin.qq.com/sns/userinfo";
		paramMap.clear();
		paramMap.put("access_token", accessTokenStr);
		paramMap.put("openid", openid);
		
		String userinfoResponse = HttpClientUtil.doPostSSL(userinfoURL, paramMap);
		UserInfo userinfo = json.fromJson(userinfoResponse, UserInfo.class);

		log.info("--userinfo: " + userinfo);
		
		return CODE;
	}

	
	
// https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
	public AccessToken requestAccessToken(String code, JsonMapper json) {		
		String accessTokenURL = "https://api.weixin.qq.com/sns/oauth2/access_token";
		
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("appid", AppID);
		paramMap.put("secret", AppSecret);
		paramMap.put("code", code);
		paramMap.put("grant_type", "authorization_code");
		
		String accessTokenResponse = HttpClientUtil.doPostSSL(accessTokenURL, paramMap);
		AccessToken accessToken = json.fromJson(accessTokenResponse, AccessToken.class);
		AccessTokenHelper accessTokenHelper = AccessTokenHelper.getInstance();
		
		int expiresIn = accessToken.getExpires_in();
		Date expireEndDate = DateUtil.addSeconds(new Date(), expiresIn);
		accessTokenHelper.setExpireInDate(expireEndDate);
		accessTokenHelper.setAccessToken(accessToken);
		
		return accessToken;
	}
}

该代码用到json.fromJson()用于将json数据转为实体类,大家可以将该方法替换成自己的方法

 HttpClientUtil.doPostSSL():是用于发送https请求的方法,大家可以将该方法替换成自己的方法


整篇文章一直在强调要AppID使用微信开放平台网站应用AppID,

微信开放平台:登录:https://open.weixin.qq.com ---》 管理中心------》网站应用   如果你还没有网站应用那就必须创建一个网站应用,提交审核好像是要收费300元的

技术分享

当Oauth2Controller开发后,放到测试环境中,此时要注意测试环境的服务器的JDK,不能使用OpenJDK,要使用Sun的SDK,否则在发送https请求会报错。

至此:微信已认证的订阅号授权登录功能就算完了,如有问题请评论


参考文章: http://www.cnblogs.com/txw1958/p/weixin71-oauth20.html


微信公众号之订阅号(已认证)实现oauth2授权登录详细步骤介绍

标签:

(1)
(2)
   
举报
评论 一句话评论(0
0条  
登录后才能评论!
© 2014 mamicode.com 版权所有 京ICP备13008772号-2
迷上了代码!