分享一个朋友的人工智能教程(请以“右键”->"在新标签页中打开连接”的方式访问)。比较通俗易懂,风趣幽默,感兴趣的朋友可以去看看。
一: 简介
通过 微信公众平台---->权限接口 可以得知 微信的订阅号是没有授权登录接口的,只有服务号才有该权限。这点微信公众平台在多处反复强调
最终的事实是:微信订阅号是可以实现授权登录的!
二:具体实现步骤:
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×tamp=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请求会报错。
注意:有的评论说这篇博客帮助了他,有的说博客内容有误,我也不是很清楚,我只是把我在公司做的这个功能记录上来,上线也一直在用,具体博客内容有没有问题请大家自己判断,毕竟不是所有的博客都100%的对,本人水平有限
参考文章: http://www.cnblogs.com/txw1958/p/weixin71-oauth20.html