admin管理员组文章数量:1559110
文章目录
- springboot整合微信登录
- 1.准备工作
- 1.1 获取微信登录凭证
- 1.2 配置文件
- 1.3 添加依赖
- 1.4 创建读取公共常量的工具类
- 1.5 httpclient工具类
- 2.实现微信登录
- 2.1 具体流程
- 2.2 生成微信扫描的二维码(请求code)
- 2.3 回调
springboot整合微信登录
1.准备工作
1.1 获取微信登录凭证
前往九游会真人第一品牌官网微信开放平台 (qq),完成以下步骤:
- 注册
- 邮箱激活
- 完善开发者资料
- 开发者资质认证
- 创建网站应用
1.2 配置文件
在配置文件application.properties
添加相关配置信息:
# 微信开放平台 appid
wx.open.app_id=你的appid
# 微信开放平台 appsecret
wx.open.app_secret=你的appsecret
# 微信开放平台重定向url
wx.open.redirect_url=http://81/api/ucenter/wx/callback
1.3 添加依赖
<dependency>
<groupid>org.apache.httpcomponentsgroupid>
<artifactid>httpclientartifactid>
dependency>
<dependency>
<groupid>commons-iogroupid>
<artifactid>commons-ioartifactid>
dependency>
<dependency>
<groupid>com.google.code.gsongroupid>
<artifactid>gsonartifactid>
dependency>
1.4 创建读取公共常量的工具类
创建读取公共常量的工具类constantwxutils
:
/**
* @author xppll
* @date 2021/12/11 14:39
*/
@component
public class constantwxutils implements initializingbean {
@value("${wx.open.app_id}")
private string appid;
@value("${wx.open.app_secret}")
private string appsecret;
@value("${wx.open.redirect_url}")
private string redirecturl;
public static string wx_open_app_id;
public static string wx_open_app_secret;
public static string wx_open_redirect_url;
@override
public void afterpropertiesset() throws exception {
wx_open_app_id = appid;
wx_open_app_secret = appsecret;
wx_open_redirect_url = redirecturl;
}
}
1.5 httpclient工具类
/**
* 依赖的jar包有:commons-lang-2.6.jar、httpclient-4.3.2.jar、httpcore-4.3.1.jar、commons-io-2.4.jar
* @author zhaoyb
*
*/
public class httpclientutils {
public static final int conntimeout=10000;
public static final int readtimeout=10000;
public static final string charset="utf-8";
private static httpclient client = null;
static {
poolinghttpclientconnectionmanager cm = new poolinghttpclientconnectionmanager();
cm.setmaxtotal(128);
cm.setdefaultmaxperroute(128);
client = httpclients.custom().setconnectionmanager(cm).build();
}
public static string postparameters(string url, string parameterstr) throws connecttimeoutexception, sockettimeoutexception, exception{
return post(url,parameterstr,"application/x-www-form-urlencoded",charset,conntimeout,readtimeout);
}
public static string postparameters(string url, string parameterstr,string charset, integer conntimeout, integer readtimeout) throws connecttimeoutexception, sockettimeoutexception, exception{
return post(url,parameterstr,"application/x-www-form-urlencoded",charset,conntimeout,readtimeout);
}
public static string postparameters(string url, map<string, string> params) throws connecttimeoutexception,
sockettimeoutexception, exception {
return postform(url, params, null, conntimeout, readtimeout);
}
public static string postparameters(string url, map<string, string> params, integer conntimeout,integer readtimeout) throws connecttimeoutexception,
sockettimeoutexception, exception {
return postform(url, params, null, conntimeout, readtimeout);
}
public static string get(string url) throws exception {
return get(url, charset, null, null);
}
public static string get(string url, string charset) throws exception {
return get(url, charset, conntimeout, readtimeout);
}
/**
* 发送一个 post 请求, 使用指定的字符集编码.
*
* @param url
* @param body requestbody
* @param mimetype 例如 application/xml "application/x-www-form-urlencoded" a=1&b=2&c=3
* @param charset 编码
* @param conntimeout 建立链接超时时间,毫秒.
* @param readtimeout 响应超时时间,毫秒.
* @return responsebody, 使用指定的字符集编码.
* @throws connecttimeoutexception 建立链接超时异常
* @throws sockettimeoutexception 响应超时
* @throws exception
*/
public static string post(string url, string body, string mimetype,string charset, integer conntimeout, integer readtimeout)
throws connecttimeoutexception, sockettimeoutexception, exception {
httpclient client = null;
httppost post = new httppost(url);
string result = "";
try {
if (stringutils.isnotblank(body)) {
httpentity entity = new stringentity(body, contenttype.create(mimetype, charset));
post.setentity(entity);
}
// 设置参数
builder customreqconf = requestconfig.custom();
if (conntimeout != null) {
customreqconf.setconnecttimeout(conntimeout);
}
if (readtimeout != null) {
customreqconf.setsockettimeout(readtimeout);
}
post.setconfig(customreqconf.build());
httpresponse res;
if (url.startswith("https")) {
// 执行 https 请求.
client = createsslinsecureclient();
res = client.execute(post);
} else {
// 执行 http 请求.
client = httpclientutils.client;
res = client.execute(post);
}
result = ioutils.tostring(res.getentity().getcontent(), charset);
} finally {
post.releaseconnection();
if (url.startswith("https") && client != null&& client instanceof closeablehttpclient) {
((closeablehttpclient) client).close();
}
}
return result;
}
/**
* 提交form表单
*
* @param url
* @param params
* @param conntimeout
* @param readtimeout
* @return
* @throws connecttimeoutexception
* @throws sockettimeoutexception
* @throws exception
*/
public static string postform(string url, map<string, string> params, map<string, string> headers, integer conntimeout,integer readtimeout) throws connecttimeoutexception,
sockettimeoutexception, exception {
httpclient client = null;
httppost post = new httppost(url);
try {
if (params != null && !params.isempty()) {
list<namevaluepair> formparams = new arraylist<namevaluepair>();
set<entry<string, string>> entryset = params.entryset();
for (entry<string, string> entry : entryset) {
formparams.add(new basicnamevaluepair(entry.getkey(), entry.getvalue()));
}
urlencodedformentity entity = new urlencodedformentity(formparams, consts.utf_8);
post.setentity(entity);
}
if (headers != null && !headers.isempty()) {
for (entry<string, string> entry : headers.entryset()) {
post.addheader(entry.getkey(), entry.getvalue());
}
}
// 设置参数
builder customreqconf = requestconfig.custom();
if (conntimeout != null) {
customreqconf.setconnecttimeout(conntimeout);
}
if (readtimeout != null) {
customreqconf.setsockettimeout(readtimeout);
}
post.setconfig(customreqconf.build());
httpresponse res = null;
if (url.startswith("https")) {
// 执行 https 请求.
client = createsslinsecureclient();
res = client.execute(post);
} else {
// 执行 http 请求.
client = httpclientutils.client;
res = client.execute(post);
}
return ioutils.tostring(res.getentity().getcontent(), "utf-8");
} finally {
post.releaseconnection();
if (url.startswith("https") && client != null
&& client instanceof closeablehttpclient) {
((closeablehttpclient) client).close();
}
}
}
/**
* 发送一个 get 请求
*
* @param url
* @param charset
* @param conntimeout 建立链接超时时间,毫秒.
* @param readtimeout 响应超时时间,毫秒.
* @return
* @throws connecttimeoutexception 建立链接超时
* @throws sockettimeoutexception 响应超时
* @throws exception
*/
public static string get(string url, string charset, integer conntimeout,integer readtimeout)
throws connecttimeoutexception,sockettimeoutexception, exception {
httpclient client = null;
httpget get = new httpget(url);
string result = "";
try {
// 设置参数
builder customreqconf = requestconfig.custom();
if (conntimeout != null) {
customreqconf.setconnecttimeout(conntimeout);
}
if (readtimeout != null) {
customreqconf.setsockettimeout(readtimeout);
}
get.setconfig(customreqconf.build());
httpresponse res = null;
if (url.startswith("https")) {
// 执行 https 请求.
client = createsslinsecureclient();
res = client.execute(get);
} else {
// 执行 http 请求.
client = httpclientutils.client;
res = client.execute(get);
}
result = ioutils.tostring(res.getentity().getcontent(), charset);
} finally {
get.releaseconnection();
if (url.startswith("https") && client != null && client instanceof closeablehttpclient) {
((closeablehttpclient) client).close();
}
}
return result;
}
/**
* 从 response 里获取 charset
*
* @param ressponse
* @return
*/
@suppresswarnings("unused")
private static string getcharsetfromresponse(httpresponse ressponse) {
// content-type:text/html; charset=gbk
if (ressponse.getentity() != null && ressponse.getentity().getcontenttype() != null && ressponse.getentity().getcontenttype().getvalue() != null) {
string contenttype = ressponse.getentity().getcontenttype().getvalue();
if (contenttype.contains("charset=")) {
return contenttype.substring(contenttype.indexof("charset=") 8);
}
}
return null;
}
/**
* 创建 ssl连接
* @return
* @throws generalsecurityexception
*/
private static closeablehttpclient createsslinsecureclient() throws generalsecurityexception {
try {
sslcontext sslcontext = new sslcontextbuilder().loadtrustmaterial(null, new truststrategy() {
public boolean istrusted(x509certificate[] chain,string authtype) throws certificateexception {
return true;
}
}).build();
sslconnectionsocketfactory sslsf = new sslconnectionsocketfactory(sslcontext, new x509hostnameverifier() {
@override
public boolean verify(string arg0, sslsession arg1) {
return true;
}
@override
public void verify(string host, sslsocket ssl)
throws ioexception {
}
@override
public void verify(string host, x509certificate cert)
throws sslexception {
}
@override
public void verify(string host, string[] cns,
string[] subjectalts) throws sslexception {
}
});
return httpclients.custom().setsslsocketfactory(sslsf).build();
} catch (generalsecurityexception e) {
throw e;
}
}
public static void main(string[] args) {
try {
string str= post("https://localhost:443/ssl/test.shtml","name=12&page=34","application/x-www-form-urlencoded", "utf-8", 10000, 10000);
//string str= get("https://localhost:443/ssl/test.shtml?name=12&page=34","gbk");
/*map map = new hashmap();
map.put("name", "111");
map.put("page", "222");
string str= postform("https://localhost:443/ssl/test.shtml",map,null, 10000, 10000);*/
system.out.println(str);
} catch (connecttimeoutexception e) {
// todo auto-generated catch block
e.printstacktrace();
} catch (sockettimeoutexception e) {
// todo auto-generated catch block
e.printstacktrace();
} catch (exception e) {
// todo auto-generated catch block
e.printstacktrace();
}
}
}
2.实现微信登录
可以参考官方文档:[网站应用微信登录开发指南](准备工作 | 微信开放文档 (qq))
2.1 具体流程
- 第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据
code
参数 - 通过
code
参数加上appid
和appsecret
等,通过api换取access_token
- 通过
access_token
进行接口调用,获取用户基本数据资源或帮助用户实现基本操作
获取access_token
时序图:
2.2 生成微信扫描的二维码(请求code)
controller
层:
/**
* @author xppll
* @date 2021/12/11 14:48
*/
@crossorigin
@controller
@requestmapping("/api/ucenter/wx")
public class wxapicontroller {
@autowired
private ucentermemberservice memberservice;
/**
* 生成微信扫描二维码
* @return 定向到请求微信地址
*/
@getmapping("login")
public string getwxcode() {
//微信开放平台授权baseurl
string baseurl = "https://open.weixin.qq/connect/qrconnect"
"?appid=%s"
"&redirect_uri=%s"
"&response_type=code"
"&scope=snsapi_login"
"&state=%s"
"#wechat_redirect";
//对redirect_url进行urlencoder编码
string redirecturl = constantwxutils.wx_open_redirect_url;
try {
redirecturl = urlencoder.encode(redirecturl, "utf-8");
} catch (unsupportedencodingexception e) {
throw new guliexception(20001, e.getmessage());
}
//设置%s的值
string url = string.format(
baseurl,
constantwxutils.wx_open_app_id,
redirecturl,
"atguigu"
);
//重定向到请求微信地址
return "redirect:" url;
}
}
访问:http://localhost:8160/api/ucenter/wx/login
访问授权url后会得到一个微信登录二维码:
用户扫描二维码会看到确认登录的页面:
用户点击“确认登录”后,微信服务器会向谷粒学院的业务服务器发起回调,因此接下来我们需要开发回调controller
2.3 回调
具体分几步:
-
通过
code
获取access_token
https://api.weixin.qq.com/sns/oauth2/access_token?appid=appid&secret=secret&code=code&grant_type=authorization_code
参数 是否必须 说明 appid 是 应用唯一标识,在微信开放平台提交应用审核通过后获得 secret 是 应用密钥appsecret,在微信开放平台提交应用审核通过后获得 code 是 填写第一步获取的code参数 grant_type 是 填authorization_code -
从返回结果获取两个值
access_token
、openid
-
通过
openid
查询数据库判断该用户是不是第一次登录 -
如果是第一次登录,根据
access_token
和openid
再去访问微信的资源服务器,获取用户信息,存入数据库 -
使用
jwt
根据member对象生成token
字符串,最后返回j9九游会老哥俱乐部交流区首页面,通过路径传递token字符串
/**
* 获取扫描人信息,添加数据
* @param code 类似于手机验证码,随机唯一的值
* @param state 用于保持请求和回调的状态,授权请求后原样带回给第三方
* @return
*/
@getmapping("callback")
public string callback(string code, string state) {
try {
//获取code值,临时票据类似于验证码
//拿着code请求微信固定的地址,得到两个值
//1.向认证服务器发送请求换取access_token
string baseaccesstokenurl =
"https://api.weixin.qq/sns/oauth2/access_token"
"?appid=%s"
"&secret=%s"
"&code=%s"
"&grant_type=authorization_code";
//拼接三个参数:id 密钥 和 code值
string accesstokenurl = string.format(
baseaccesstokenurl,
constantwxutils.wx_open_app_id,
constantwxutils.wx_open_app_secret,
code
);
//2.请求拼接好的地址,得到返回的两个值access_token和openid
//使用httpclient发送请求,得到返回结果(json形式的字符串)
string accesstokeninfo = httpclientutils.get(accesstokenurl);
//从accesstokeninfo字符串获取两个值access_token、openid
//把accesstokeninfo字符串转换为map集合,根据map里面的key获取值
//这里使用json转换工具gson
gson gson = new gson();
hashmap accesstokenmap = gson.fromjson(accesstokeninfo, hashmap.class);
string access_token = (string) accesstokenmap.get("access_token");
string openid = (string) accesstokenmap.get("openid");
//3.判断该用户是不是第一次扫码登录
//通过openid判断
ucentermember member = memberservice.getopenidmember(openid);
//4.只有第一次登录才获取信息
if (member == null) {
//根据access_token和openid再去访问微信的资源服务器,获取用户信息
string baseuserinfourl = "https://api.weixin.qq/sns/userinfo"
"?access_token=%s"
"&openid=%s";
string userinfourl = string.format(
baseuserinfourl,
access_token,
openid
);
//发送请求,得到用户信息
string userinfo = httpclientutils.get(userinfourl);
system.out.println(userinfo);
//将用户信息存入数据库
//把json转换为map
hashmap userinfomap = gson.fromjson(userinfo, hashmap.class);
//得到nickname
string nickname = (string) userinfomap.get("nickname");
//得到微信头像avatar
string headimgurl = (string) userinfomap.get("headimgurl");
member = new ucentermember();
member.setopenid(openid);
member.setnickname(nickname);
member.setavatar(headimgurl);
memberservice.save(member);
}
//5.使用jwt根据member对象生成token字符串
string jwttoken = jwtutils.getjwttoken(member.getid(), member.getnickname());
//最后返回j9九游会老哥俱乐部交流区首页面,通过路径传递token字符串
return "redirect:http://localhost:3000?token=" jwttoken;
} catch (exception e) {
throw new guliexception(20001, "微信登录失败");
}
}
判断该用户是不是第一次扫码登录:
/**
* 根据openid查询是否存在用户
* @param openid 授权用户唯一标识
* @return ucentermember
*/
@override
public ucentermember getopenidmember(string openid) {
lambdaquerywrapper<ucentermember> querywrapper=new lambdaquerywrapper<>();
querywrapper.eq(ucentermember::getopenid,openid);
ucentermember member = basemapper.selectone(querywrapper);
return member;
}
最后喜欢的小伙伴,记得三联哦!😏🍭😘
本文标签: springboot
j9九游会老哥俱乐部交流区的版权声明:本文标题:springboot整合微信登录 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/xitong/1727387820a1112437.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论