java实现微信扫码登录第三方网站功能(原理和代码)
作者:yin 发布时间:2023-08-04 00:44:11
为避免繁琐的注册登陆,很多平台和网站都会实现三方登陆的功能,增强用户的粘性。这篇文章主要介绍了java实现微信扫码登录第三方网站功能(原理和代码),避免做微信登录开发的朋友们少走弯路。
一.查看微信扫码登录官方文档
官方文档:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=&lang=zh_CN
1.在进行第三方授权登录之前,需要在微信开放平台注册开发者账号,拿到相应的AppId和AppSecret以及redirect_uri,即可进行授权接入流程;
2.第三方可以获取到用户的接口调用凭证(access_token),通过access_token可以进行微信开放平台授权关系接口调用,从而可实现获取微信用户基本开放信息和帮助用户实现基础开放功能等。
获取access_token时序图:
二.实现微信第三方登录流程:
1. 开发者调用微信接口用于获取扫描二维码。
调用接口:
https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
参数介绍:
appid: 微信申请已存在的服务号的应用号;
redirect_uri: 回调地址,扫完码之后微信会将code这个值传到这个地址上,注意:回调地址需要用urlEncode处理;
responseType: 填code;
scope: 网页应用仅填snsapi_login;
state: 用于保持请求和回调的状态,授权请求后原样带给第三方,可用于防止跨站攻击;
2. 用户扫描二维码后该接口会自动返回重定向的资源上,并且带上code和state参数,如果用户拒绝授权只会带上state参数
3. 开发者通过用微信另一个接口根据code和 appid,secret获取access_token(也就是调用接口的凭证,有了他可以获取里面的openid等信息)
调用接口:
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
参数介绍
appid: 微信申请已存在的服务号的应用号;
secret:微信申请已存在的应用密匙;
code:调用上面一个接口自动返回的临时票据。
grant_type:写authorization_code
返回参数介绍
示例:
{
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE"
}
access_token:接口调用凭证
expires_in:access_token接口调用凭证超时时间,单位(秒)
refresh_token: 用户刷新access_token
openid:授权用户唯一标识(常用)
scope:用户授权的作用域
4.调用接口根据access_token和openid获取个人用户信息
调用接口:
http请求方式: GET
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
access_token:上个接口调用后返回的调用凭证
openid:上个接口获取的授权用户唯一标识返回参数介绍
示例;
{
"openid":"OPENID",
"nickname":"NICKNAME",
"sex":1,
"province":"PROVINCE",
"city":"CITY",
"country":"COUNTRY",
"headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
"privilege":["PRIVILEGE1","PRIVILEGE2"],
"unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
}
openid:授权用户唯一标识
nickname:普通用户昵称
sex:普通用户性别,1为男性,2为女性
province:普通用户个人资料填写的省份
city:普通用户个人资料填写的城市
country:国家,如中国为CN
headimgurl:用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空
privilege:用户特权信息,json数组,如微信沃卡用户为(chinaunicom)
unionid:用户统一标识。针对一个微信开放平台帐号下的应用,同一用户的unionid是唯一的。
三.代码实现:
1.创建相关工具类
封装的几个基础类
a. access_token封装基础类
public class Token {
private String openid; //授权用户唯一标识
private String accessToken; //接口调用凭证
private Integer ExpiresIn; //access_token接口调用凭证超时时间,单位(秒)
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public Integer getExpiresIn() {
return ExpiresIn;
}
public void setExpiresIn(Integer expiresIn) {
ExpiresIn = expiresIn;
}
b. 根据openid获取用户信息封装成基础类
public class WechatUserInfo {
private String unionid; //用户唯一标识
private String nickname; //昵称
private String headimgurl; //头像地址
private String subscribe; // 用户是否订阅该公众号标识,值为0时,代表此用户没有关注该公众号,拉取不到其余信息。 1 用户已经绑定公众号
public String getUnionid() {
return unionid;
}
public void setUnionid(String unionid) {
this.unionid = unionid;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getHeadimgurl() {
return headimgurl;
}
public void setHeadimgurl(String headimgurl) {
this.headimgurl = headimgurl;
}
public String getSubscribe() {
return subscribe;
}
public void setSubscribe(String subscribe) {
this.subscribe = subscribe;
}
工具类
a. urlEncodeUTF8工具类(用于将扫描二维码后重定向的资源url进行编码)
public static String urlEncodeUTF8(String source){
String result = source;
try {
result = java.net.URLEncoder.encode(source,"utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return result;
}
b. httpsRequest工具类(用于处理微信的获取openid和用户信息的接口的请求调用,返回相应的数据)
/**
* 发送https请求
* @param requestUrl 请求地址
* @param requestMethod 请求方式(GET、POST)
* @param outputStr 提交的数据
* @return 返回微信服务器响应的信息
*/
public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
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);
conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
// 当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();
return buffer.toString();
} catch (ConnectException ce) {
log.error("连接超时:{}", ce);
} catch (Exception e) {
log.error("https请求异常:{}", e);
}
return null;
}
c. 获取openid等信息的方法
public static Token getTokenWithOpenid(String appid, String appsecret, String code) {
String findAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
Token token = null;
String requestUrl = findAccessTokenUrl.replace("APPID", appid).replace("SECRET", appsecret).replace("CODE", code);// 发起GET请求获取凭证
JSONObject jsonObject = JSONObject.fromObject(httpsRequest(requestUrl, "GET", null));
if (null != jsonObject) {
try {
token = new Token();
token.setOpenid(jsonObject.getString("openid"));
token.setAccessToken(jsonObject.getString("access_token"));
token.setExpiresIn(jsonObject.getInt("expires_in"));
} catch (JSONException e) {
token = null;
// 获取token失败
log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));
}
}
return token;
}
d. 根据openid获取用户信息的方法
public static WechatUserInfo getUserinfo(String access_token, String openid) {
WechatUserInfo wxuse = new WechatUserInfo();
String findUseinfo = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID";
String requestUrl = findUseinfo.replace("ACCESS_TOKEN", access_token).replace("OPENID", openid);
JSONObject jsonObject = JSONObject.fromObject(httpsRequest(requestUrl, "GET", null));
if (null != jsonObject) {
try {
wxuse.setNickname(jsonObject.getString("nickname"));
wxuse.setHeadimgurl(jsonObject.getString("headimgurl"));
wxuse.setUnionid(jsonObject.getString("unionid"));
} catch (JSONException e) {
e.printStackTrace();
}
}
return wxuse;
}
操作:
a. 跳转至登录授权页面(页面出现二维码)
public String weChatLanded(){
String requestUrl = "https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect";
String loginAppid = "wxea43f181e32e8df0"; //微信申请的appid
String loginRedirectUrl = "https://www.jb51.net/weChatLogin_epf.action";//调用微信接口后返回的资源名
String loginScope = "snsapi_login";//写死
redirectURL = requestUrl.replace("APPID", loginAppid).replace("REDIRECT_URI", CommonUtil.urlEncodeUTF8(loginRedirectUrl)).replace("SCOPE", loginScope);
return SUCCESS;
}
b. 授权成功后:
@SuppressWarnings("static-access")
public String weChatLogin_epf(){
//通过code获取access_token
String loginAppid = "wxea43f181e32e8df0";
String loginSecrect = "4721e5f744e6c0f3c4094b25449ee7e3";
Token tokenWithOpenid = CommonUtil.getTokenWithOpenid(loginAppid, loginSecrect,code);
String openid = tokenWithOpenid.getOpenid();
String access_token = tokenWithOpenid.getAccessToken();
//通过access_token调用接口
WechatUserInfo wxuse = CommonUtil.getUserinfo(access_token, openid);
return SUCCESS;
}
猜你喜欢
- 当数据库中数据条数过多时,一个页面就不能显示,这是要设置分页查询,首先要使用的是数据库sql语句的limit条件实现分组查询sql语句大概形
- 前言本文主要给大家介绍了关于Spring Boot应用极速部署脚本的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧
- SpringBoot配置文件中设置server.port不生效我的配置文件为:# application.ymlserver:
- 1 线程池的优势总体来说,线程池有如下的优势:(1)降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。(2)提高响应速度。
- 一、RESTful风格API的好处API(Application Programming Interface),顾名思义:是一组编程接口规范
- 下面是我做C#第一个项目的过程:1.首先打开VS,这里我用的是VS2022预览版,鼠标双击打开VS;图一2.打开VS后会出现下面的页面,鼠标
- openFeign服务间调用保持请求头信息处理1、注意特殊情况,在定时任务或者内部之间调用,没有request的时候,不要处理直接返回。2、
- 前言之前采取项目中嵌套html页面,实现基本的登录校验、权限校验、登出操作、记住我等功能试下。但是,现在的开发基本都是前后分离样式,后端并不
- 我有以下课程public class ModInfo : IEquatable<ModInfo>{ public int ID
- Java集合是java提供的工具包,包含了常用的数据结构:集合、链表、队列、栈、数组、映射等。Java集合工具包位置是java.util.*
- 本文提供了基于MD5加密16位和32位的方法,具体内容如下import java.io.IOException;import java.ma
- 背景介绍1,最近有一个大数据量插入的操作入库的业务场景,需要先做一些其他修改操作,然后在执行插入操作,由于插入数据可能会很多,用到多线程去拆
- 前言本文主要给大家介绍的是java虚拟机的故障处理工具,文中提到这些工具包括:名称主要作用jpsJVM process Status Too
- 从主线程发送消息到子线程(准确地说应该是非UI线程)package com.zhuozhuo;import android.app.Acti
- 本文实例讲述了Android自定义dialog简单实现方法。分享给大家供大家参考,具体如下:@Override protected void
- MVC三层架构我们在刚刚成为程序员的时候,就会被前辈们 “教育” 说系统的设计要遵循 MVC(Model-View-Controller)架
- 在项目中我们肯定不能使用Spring自己生成的登录页面,而要用我们自己的登录页面,下面讲一下如何自定义登录页面,先看下配置<sec:h
- 小总结抛出异常:创建异常对象,封装异常信息然后通过throw将异常对象传递给调用者。不对异常进行处理只对异常进行抛出是非常不负责任的表现可以
- 1. JVM 运行时数据区JVM运行时数据区可以分为元空间,堆,虚拟机栈,本地方法栈,程序计数器五大块。元空间(方法区):存放类模版对象,是
- Java事件处理机制java中的事件机制的参与者有3种角色:1.event object:事件状态对象,用于listener的相应的方法之中