互联网时代,不管是以哪种形式存在的应用,移动端或者PC网站,注册登录功能是用户访问应用的第一步,可以说,注册登录用的方不方便在一定程度上能决定用户的去留。对于用户来说,能够越简单,不用动手做过多操作就能达到同样效果的功能是最好不过的。今天就来介绍一下PC网站如何通过扫描微信二维码关注公众号,直接完成注册登录。
1、思考
最近在刷乐观数据的时候,发现网站注册登录流程有点不一样,都没怎么操作,只是用手机扫了一个二维码进入到关注公众号的页面,然后关注公众号,就收到登入成功的消息提醒,电脑上也直接进入到平台首页,而且还显示了我的微信头像、昵称,很是快速。
这一看就不是用扫描微信开放平台的那种二维码做的,这种还更轻巧些,那这是怎么实现的呢?于是就去翻阅微信开发文档理了一下,就明白了。
2、思路
其实这个功能实现原理很简单,如果按公众号开发文档的步骤来就两步:
账号管理 -> 生成带参数二维码接口-> 创建临时二维码
消息管理 -> 接收事件推送 -> 扫描带参数二维码事件
接下来 来看开发过程,注意,已微信认证的服务号才有生成带参数二维码的功能
3、开发
关于二维码,微信根据实际业务不同提供了两种创建方法,临时和永久的,其实也什么差别,这里就举例说明创建临时二维码。
3.1 生成调用凭据access_token(这个要做缓存,第一次先存缓存,之后都从缓存取,过期了再重新获取,这里没有做缓存)
/**
* @description
*/
@Component
public class GetToken {
private Logger logger = LoggerFactory.getLogger(GetToken.class);
public AccessToken getToken(String appid, String appSecrect) {
AccessToken token;
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid
+ "&secret=" + appSecrect;
String result = CommonUtil.httpsRequest(url, "GET", null);
JSONObject jsonObject = JSONObject.fromObject(result);
if (jsonObject != null) {
try {
token = new AccessToken();
token.setAccess_token(jsonObject.getString("access_token"));
token.setExpires_in(jsonObject.getLong("expires_in"));
} catch (Exception e) {
token = null;
e.printStackTrace();
logger.error("系统出错了!");
}
} else {
token = null;
// 获取token失败
logger.error("jsonObject为空,获取token失败");
}
return token;
}
}
工具类 CommonUtil
/**
*
* @Description: 通用工具类
*
*/
public class CommonUtil {
private static Logger log = LoggerFactory.getLogger(CommonUtil.class);
/**
*
* @Title: httpsRequestJson
* @Description: 发送https请求 ---返回JSONObject
* @param requestUrl 请求地址
* @param requestMethod 请求方式(GET、POST)
* @param outputStr 提交的数据
* @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
* @return JSONObject 返回类型
* @throws
*/
public static JSONObject httpsRequestJson(String requestUrl, String requestMethod,
String outputStr) {
JSONObject jsonObject = null;
try {
// 创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = { new MyX509TrustManager() };
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(ssf);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
// 设置请求方式(GET/POST)
conn.setRequestMethod(requestMethod);
// 当outputStr不为null时向输出流写数据
if (null != outputStr) {
OutputStream outputStream = conn.getOutputStream();
// 注意编码格式
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 从输入流读取返回内容
InputStream inputStream = conn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
StringBuffer buffer = new StringBuffer();
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
// 释放资源
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
inputStream = null;
conn.disconnect();
jsonObject = JSONObject.parseObject(buffer.toString());
} catch (ConnectException ce) {
} catch (Exception e) {
}
return jsonObject;
}
}
生成二维码,
scene_id这个字段是自定义的场景值,比如我们这个扫码场景是注册登录,在处理事件推送那边可以取到,用来判断场景。
* @Description
*/
public class WxPublicQrcode {
private static final String createUrl = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=";
private static final String showqrcodeUrl = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=";
@Autowired
private GetToken getToken;
/**
* 1、创建二维码ticket
* @return
* {"ticket":"gQH47joAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL2taZ2Z3TVRtNzJXV1Brb3ZhYmJJAAIEZ23sUwMEmm
* 3sUw==","expire_seconds":60,"url":"http://weixin.qq.com/q/kZgfwMTm72WWPkovabbI" }
*/
public static JSONObject create () {
String token = getToken.getToken("appid","appSecrect").getAccess_token();
Map<String, Object> map = new HashMap<>();
map.put("expire_seconds",60);
map.put("action_name","QR_SCENE");
Map<String,Object> sceneId = new HashMap<>();
sceneId.put("scene_id",123);
Map<String, Object> scene = new HashMap<>();
scene.put("scene",sceneId);
map.put("action_info",scene);
String param = JSON.toJSONString(map);
System.out.println(param);
JSONObject jsonObject = CommonUtil.httpsRequestJson(createUrl+token, "POST", param);
System.out.println(jsonObject);
return jsonObject;
}
/**
* 2、通过ticket换取二维码
* @return ticket正确情况下,http 返回码是200,是一张图片,可以直接展示或者下载
*/
public static JSONObject showqrcode () {
JSONObject create = create();
String ticket = create.getString("ticket");
try {
ticket = URLEncoder.encode(ticket,"utf-8");
JSONObject jsonObject = CommonUtil.httpsRequestJson(showqrcodeUrl+ ticket, "GET", null);
System.out.println(jsonObject);
return jsonObject;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
}
3.2 处理事件推送
关于如何处理接收事件,参考微信公众号关注或取关后再处理我们自己的业务逻辑这篇文章。
判断Event值是subscribe且EventKey值是qrscene_为前缀,后面为二维码的参数值,那么就是用户还未关注公众号,则用户可以关注公众号,做各种操作,存数据库什么,FromUserName就是用户的openid,Event值是SCAN且EventKey值是是一个32位无符号整数,即创建二维码时的二维码scene_id,则用户已经关注公众号,再做相对应的操作。
山水有相逢,来日皆可期,谢谢阅读,我们再会
我手中的金箍棒,上能通天,下能探海