网站登录
一. 开发准备
1. 注册企业账号
在微信开放平台注册账号。
2. 企业开发平台认证
完成企业信息认证,获得开发权限。
3. 创建网站应用
注意:需要等待审核1-7天,审核成功腾讯会给你提供AppID和AppSecret
填写文件
open.weixin.qq.com/zh_CN/htmle…
4. 配置回调地址
无需带上http或者https
注意:有个测试账号是公众号使用的不是应用网站。
这个是微信公众平台,不是开放平台。
微信公众平台开发是指为微信公众号进行业务开发,为移动应用、PC端网站、公众号第三方平台(为各行各业公众号运营者提供服务)的开发,请前往微信开放平台接入。
5. 注意事项:
企业账号与开发者资质认证主体保持一致。
developers.weixin.qq.com/doc/oplatfo…
所提供的官网不得是无法访问应用详细信息的登录界面,如网站需登录后才可访问,建议提供相关账号密码以供审核人员登录并查看相关信息。
提交的官网主体信息或者应用市场下载链接开发者信息,需与微信开放平台认证主体信息一致,如不一致,可在提审基本信息页面的流程图处附上授权书,授权书可自行拟定,需说明清楚授权关系、授权内容,并加盖双方公司公章,个人主体则签名即可。
你所提交的官网开发者信息,需要与微信开放平台开发者资质认证主体信息一致,如不一致,提交时需提供相关授权书(加盖双方公章) 以供审核。
二. 实现逻辑
具体逻辑:微信登录功能 / 网站应用微信登录开发指南 (qq.com)
用户登录原理图:
微信调用逻辑图:
① 第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据code参数;
② 通过code参数加上AppID和AppSecret等,通过API换取access_token;
code的超时时间为10分钟,一个code只能成功换取一次access_token 即失效。code的临时性和一次性保障了微信授权登录的安全性。
③ 通过access_token进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。
这里以谷粒学院账号演示,可以成功。
- 配置相应的数据
# 微信开放平台 appid
wx.open.app_id=wxed9954c01bb89b47
# 微信开放平台 appsecret
wx.open.app_secret=a7482517235173ddb4083788de60b90e
# 微信开放平台 重定向url
wx.open.redirect_url=http://localhost:8160/api/wx/callback
这是谷粒学院的示例。跳转到自己的接口。
@GetMapping("login")
@ApiOperation("wxlogin")
public String getWxCode() {
//1.url中的%s就相当于问号(?),代表占位符
String baseUrl = "https://open.weixin.qq.com/connect/qrconnect" +
"?appid=%s" +
"&redirect_uri=%s" +
"&response_type=code" +
"&scope=snsapi_login" +
"&state=%s" +
"#wechat_redirect";
//2.对redirect_url进行URLEncode编码
String redirect_url = ConstantWxUtils.WX_OPEN_REDIRECT_URL;
try {
redirect_url = URLEncoder.encode(redirect_url, "utf-8");
} catch(Exception e) {
}
//3.给baseUrl中的占位符(%s)赋值
String url = String.format(
baseUrl,
ConstantWxUtils.WX_OPEN_APP_ID,
redirect_url,
"0" //state目前没啥用
); //方法的返回值就是完整的带有参数的url地址
//4.重定向到请求微信地址里面
log.info(url);
return "redirect:" + url;
}
wx.open.redirect_url也是对应的回调接口地址。
回调接口,跳转到对应的网站。
@GetMapping("callback")
@ApiOperation("callback")
public String callback(String code, String state) throws Exception {
try {
//1.拿着code(这是一个临时票据,类似于验证码)请求微信给的固定地址
String baseAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token" +
"?appid=%s" +
"&secret=%s" +
"&code=%s" +
"&grant_type=authorization_code";
//1.1给地址拼接三个参数:id、秘钥、code值
String accessTokenUrl = String.format(
baseAccessTokenUrl,
ConstantWxUtils.WX_OPEN_APP_ID,
ConstantWxUtils.WX_OPEN_APP_SECRET,
code);
//1.2使用httpclient请求拼接好的地址,得到openid和access_token
String accessTokenInfo = HttpClientUtils.get(accessTokenUrl);
//输出accessTokenInfo看一下这个字符串长什么样,以便分析后面的业务逻辑
log.info(accessTokenInfo);
//从json字符串中获取openid和access_token
//使用json工具把accessTokenInfo字符串转换为map集合,根据map中的key获取对应的值
Gson gson = new Gson();
HashMap mapAccessToken = gson.fromJson(accessTokenInfo, HashMap.class);
String access_token = (String)mapAccessToken.get("access_token");
String openid = (String)mapAccessToken.get("openid");
//4.微信扫码登录时注册的过程不再由用户完成,而是由我们后端直接实现
//所以我们此时需要将用户的openid、昵称、头像加到数据库中
//根据openid判断数据库中是否已有该用户
UcenterMember member = memberService.getOpenIdMember(openid);
if (member == null) { //数据表中没有这个openid,进行添加
//2.拿着access_token和openid请求微信给的固定地址
String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
"?access_token=%s" +
"&openid=%s";
//2.1给地址拼接两个参数:access_token、openid
String userInfoUrl = String.format(baseUserInfoUrl, access_token, openid);
//2.2使用httpclient请求拼接好的地址
String userInfo = HttpClientUtils.get(userInfoUrl);
//输出userInfo看一下这个字符串长什么样,以便分析后面的业务逻辑
log.info(userInfo);
//3.获取扫码人信息
//3.1将json字符串转换为map集合
HashMap userInfoMap = gson.fromJson(userInfo, HashMap.class);
String nickname = (String) userInfoMap.get("nickname"); //用户昵称
String headimgurl = (String) userInfoMap.get("headimgurl"); //用户头像
member = new UcenterMember();
member.setOpenid(openid);
member.setNickname(nickname);
member.setAvatar(headimgurl);
member.setGmtCreate(new Date());
member.setGmtModified(new Date());
memberService.save(member);
}
//使用jwt根据member对象(对象中有用户信息)生成token字符串
String jwtToken = JwtUtils.getJwtToken(member.getId(), member.getNickname());
//返回到首页面(通过路径传递token字符串)
return "redirect:对应的网址" + jwtToken;
} catch (Exception e) {
throw new Exception(e);
}
}
工具类
@Component
public class ConstantWxUtils implements InitializingBean {
@Value("${wx.open.app_id}") //value注解用spring包里面的,别导错包
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;
}
}
sql表
CREATE TABLE `ucenter_member` (
`id` char(19) NOT NULL COMMENT '会员id',
`openid` varchar(128) DEFAULT NULL COMMENT '微信openid',
`mobile` varchar(11) DEFAULT '' COMMENT '手机号',
`password` varchar(255) DEFAULT NULL COMMENT '密码',
`nickname` varchar(50) DEFAULT NULL COMMENT '昵称',
`sex` tinyint unsigned DEFAULT NULL COMMENT '性别 1 女,2 男',
`age` tinyint unsigned DEFAULT NULL COMMENT '年龄',
`avatar` varchar(255) DEFAULT NULL COMMENT '用户头像',
`sign` varchar(100) DEFAULT NULL COMMENT '用户签名',
`is_disabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否禁用 1(true)已禁用, 0(false)未禁用',
`is_deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '逻辑删除 1(true)已删除, 0(false)未删除',
`gmt_create` datetime NOT NULL COMMENT '创建时间',
`gmt_modified` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='会员表';
如果网站既有pc又有app可以通过UnionID实现互通。
利用UnionID机制就能实现用户信息互通,因为只要是同一个微信开放平台账号下的移动应用、网站应用、公众号、小程序,用户的UnionID是唯一的(即同一用户,对同一个微信开放平台下的不同应用,UnionID是相同的),openID是应用内唯一。
微信公众号微信登录
一. 开发准备
1. 申请测试账号
微信扫码登录,获得测试账号可以测试
2. 内网穿透
内网穿透,natapp,ip地址映射-方便开发微信公众号,小程序等_natapp域名后面的真实ip-CSDN博客
二. 实现逻辑
1. 测试账号配置对应值
接口配置信息,通过调用后端接口,看是否会返回要求的值。可以通过这个调试。
// 获取AccessToken
api.weixin.qq.com/cgi-bin/tok…
如果仅是测试的话,可以直接返回不做校验。
根据内网穿透的外网地址配置。
@GetMapping("checkWxCode")
@ApiOperation("checkWxCode")
@ResponseBody
public String checkWxCode(HttpServletRequest request, HttpServletResponse response) {
// 接收微信服务器发送请求时传递过来的参数
String echostr = request.getParameter("echostr");//随机字符串
log.info(echostr);
// 直接返回echostr,即可
return echostr;
}
开发者提交信息后,微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带参数如下表所示:
| 参数 | 描述 |
|---|---|
| signature | 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。 |
| timestamp | 时间戳 |
| nonce | 随机数 |
| echostr | 随机字符串 |
开发者通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败。加密/校验流程如下:
1)将token、timestamp、nonce三个参数进行字典序排序
2)将三个参数字符串拼接成一个字符串进行sha1加密
3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信。
这是正常的校验方法。
@GetMapping("/checkWxCode")
@ResponseBody
public String checkWxCode(HttpServletRequest request, HttpServletResponse response) {
// 接收微信服务器发送请求时传递过来的参数
String signature = request.getParameter("signature"); // 微信加密签名
String timestamp = request.getParameter("timestamp"); // 时间戳
String nonce = request.getParameter("nonce"); // 随机数
String echostr = request.getParameter("echostr"); // 随机字符串
log.info("Received echostr: " + echostr);
// 校验签名
if (validateSignature(signature, timestamp, nonce)) {
return echostr;
} else {
return "Invalid signature";
}
}
private boolean validateSignature(String signature, String timestamp, String nonce) {
String[] arr = new String[]{TOKEN, timestamp, nonce};
Arrays.sort(arr);
StringBuilder content = new StringBuilder();
for (String s : arr) {
content.append(s);
}
String localSignature = byteToHex(calculateSha1(content.toString()));
return localSignature.equals(signature);
}
private String calculateSha1(String content) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] digest = md.digest(content.getBytes());
return byteToHex(digest);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("SHA-1 algorithm not found", e);
}
}
private static String byteToHex(byte[] bytes) {
StringBuilder hexString = new StringBuilder();
for (byte b : bytes) {
String hex = Integer.toHexString(0xFF & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
}
2. 扫描二维码配置测试账号
3. 设置回调页面域名
在yml里面配置
wx.open.redirect_url=http://wvk5uj.natappfree.cc/api/路径/callback
在登录方法修改一下对应url
String baseUrl = "https://open.weixin.qq.com/connect/oauth2/authorize" +
"?appid=%s" +
"&redirect_uri=%s" +
"&response_type=code" +
"&scope=snsapi_base" +
"&state=%s" +
"#wechat_redirect";
只有微信页面可以跳转到对应的网址上。
其他代码和网页登录类似。