【微信开放平台】网站使用微信第三方扫码登录(亲测可用)
1、登录微信开放平台创建网站应用,填写资料审核完成后获取AppID和AppSecret。
然后找到回调授权域名这一项 修改成要回调的域名,例如:www.baidu.com 不要加http://或https://
2、代码部分
2.1、后端第一个接口返回二维码访问界面地址给前端点击微信登录触发扫码界面
@ApiOperation("获取扫码界面访问地址")
@RequestMapping(value = "/getAddress", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public R getAddress() throws Exception {
StringBuilder param = new StringBuilder();
String url="https://open.weixin.qq.com/connect/qrconnect?";
//appid
param.append("appid=" + "wx*************222");
//回调地址 ,回调地址要进行Encode转码
String redirect_uri = "这里传重定向页面的地址例如:http://www.baidu.com/login";
//转码
param.append("&redirect_uri=" + java.net.URLEncoder.encode(redirect_uri,"UTF-8"));
//写死
param.append("&response_type=code");
//写死
param.append("&scope=snsapi_login");
return R.success().put("data",url+param.toString());
}
前端代码
调上面接口获取地址在浏览器打开
<div class="item">
< img src="../assets/img/weixin.png" alt="" @click="onWxLogin">
</div>
<script setup lang="ts">
const onWxLogin = () => {
wxLogin().then((res:any)=>{
window.location.href = (res.data);
})
}
const route = useRoute()
watch(
() => route.query,
(newValue) => {
if(newValue.code){
const loading = ElLoading.service({
lock: true,
text: '登录中',
background: 'rgba(0, 0, 0, 0.7)',
})
getWxToken({code:newValue.code,state:newValue.state}).then((res:any)=>{
neoCosToken.value = res.token
loading.close()
ElMessage.success('登录成功')
})
}
},
{ immediate: true }
)
</script>
2.2、扫码后点击允许则重定向到刚刚接口中配置的redirect_uri界面,此时该界面地址后面会出现个code值和state值,如果调用没有传递state就不会返回state 用户拒绝了登录请求,返回的结果不会有code。
2.3、接下来前端调第二个接口进行登录操作
@ApiOperation("微信扫码登录")
@RequestMapping(value = "/wxLogin", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public R wxLogin(String code,String state) throws Exception {
log.info("code:{},state{}",code,state);
if(StringUtils.isEmpty(code)){
return R.error();
}
StringBuilder param = new StringBuilder();
String url="https://api.weixin.qq.com/sns/oauth2/access_token";
param.append("appid=" + "wxc************222");
param.append("&secret=" + "056f6********************245cb47");
//这是微信回调给你的code
param.append("&code=" + code);
param.append("&grant_type=authorization_code");
String result = HttpUtils.sendGet(url, param.toString(), "UTF-8");
log.info("用户信息:{}",result);
JSONObject obj = JSONObject.parseObject(result);
String errcode = obj.getString("errcode");
if(StringUtils.isNotEmpty(errcode)){
return R.error("无效的 oauth_code");
}
String openid = obj.getString("openid");
//我这里的逻辑是拿到openid看数据库是否存在,存在直接登录,不存在自动注册游客账号登录进去。根据自己实际情况来写
return R.success();
}
返回说明
正确的返回:
{
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE",
"unionid": "o6_bma**************hMZOPfL"
}
错误返回样例:
{"errcode":40029,"errmsg":"invalid code"}
附加http工具类
package com.amicheng.common.utils.http;
import com.amicheng.common.constant.Constants;
import com.amicheng.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLConnection;
import java.security.cert.X509Certificate;
/**
* 通用http发送方法
*
*/
public class HttpUtils {
private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
/**
* 向指定 URL 发送GET方法的请求
*
* @param url 发送请求的 URL
* @return 所代表远程资源的响应结果
*/
public static String sendGet(String url) {
return sendGet(url, StringUtils.EMPTY);
}
/**
* 向指定 URL 发送GET方法的请求
*
* @param url 发送请求的 URL
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return 所代表远程资源的响应结果
*/
public static String sendGet(String url, String param) {
return sendGet(url, param, Constants.UTF8);
}
/**
* 向指定 URL 发送GET方法的请求
*
* @param url 发送请求的 URL
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @param contentType 编码类型
* @return 所代表远程资源的响应结果
*/
public static String sendGet(String url, String param, String contentType) {
StringBuilder result = new StringBuilder();
BufferedReader in = null;
try {
String urlNameString = StringUtils.isNotBlank(param) ? url + "?" + param : url;
log.info("sendGet - {}", urlNameString);
URL realUrl = new URL(urlNameString);
URLConnection connection = realUrl.openConnection();
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
connection.connect();
in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType));
String line;
while ((line = in.readLine()) != null) {
result.append(line);
}
log.info("recv - {}", result);
} catch (ConnectException e) {
log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e);
} catch (SocketTimeoutException e) {
log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e);
} catch (IOException e) {
log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e);
} catch (Exception e) {
log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e);
} finally {
try {
if (in != null) {
in.close();
}
} catch (Exception ex) {
log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
}
}
return result.toString();
}
/**
* 向指定 URL 发送POST方法的请求
*
* @param url 发送请求的 URL
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return 所代表远程资源的响应结果
*/
public static String sendPost(String url, String param) {
PrintWriter out = null;
BufferedReader in = null;
StringBuilder result = new StringBuilder();
try {
String urlNameString = url;
log.info("sendPost - {}", urlNameString);
URL realUrl = new URL(urlNameString);
URLConnection conn = realUrl.openConnection();
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty("Accept-Charset", "utf-8");
conn.setRequestProperty("contentType", "utf-8");
conn.setDoOutput(true);
conn.setDoInput(true);
out = new PrintWriter(conn.getOutputStream());
out.print(param);
out.flush();
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
String line;
while ((line = in.readLine()) != null) {
result.append(line);
}
log.info("recv - {}", result);
} catch (ConnectException e) {
log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e);
} catch (SocketTimeoutException e) {
log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e);
} catch (IOException e) {
log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e);
} catch (Exception e) {
log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e);
} finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
}
}
return result.toString();
}
public static String sendSSLPost(String url, String param) {
StringBuilder result = new StringBuilder();
String urlNameString = url + "?" + param;
try {
log.info("sendSSLPost - {}", urlNameString);
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new java.security.SecureRandom());
URL console = new URL(urlNameString);
HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty("Accept-Charset", "utf-8");
conn.setRequestProperty("contentType", "utf-8");
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setSSLSocketFactory(sc.getSocketFactory());
conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
conn.connect();
InputStream is = conn.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String ret = "";
while ((ret = br.readLine()) != null) {
if (ret != null && !"".equals(ret.trim())) {
result.append(new String(ret.getBytes("ISO-8859-1"), "utf-8"));
}
}
log.info("recv - {}", result);
conn.disconnect();
br.close();
} catch (ConnectException e) {
log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + param, e);
} catch (SocketTimeoutException e) {
log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + param, e);
} catch (IOException e) {
log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + param, e);
} catch (Exception e) {
log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + param, e);
}
return result.toString();
}
private static class TrustAnyTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
}
private static class TrustAnyHostnameVerifier implements HostnameVerifier {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
}
完事啦,欢迎各位大佬指点!!!