1、说明
本帖有两种微信扫码的方式。根据测试公众号进行测试,所以不用担心没有公众号。
因为涉及到微信回调,所以要走本地的话需要进行内网穿透,本贴不包含内网穿透教学,很简单,请自行百度。
2、测试号配置
测试号地址:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
扫码登录后,进行配置。
3、代码
3.1 依赖
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>4.3.0</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.0</version>
</dependency>
3.2 配置文件
#APPID
wx.login.appid=wx9e******e7
#secret
wx.login.appsecret=17bb2e***********ec0467
wx.login.token=weixin
#回调地址(内网穿透地址)
wx.login.server=http://elwin.*************.com
#获取二维码
wx.login.qrCodeUrl: https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=TOKEN
#基础接口的token
wx.login.tokenUrl: https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
#获取openId
wx.login.openIdUrl: https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=APPSECRET&code=CODE&grant_type=authorization_code
#获取用户
wx.login.userInfoUrl: https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
#通过ticket获取二维码
wx.login.showqrcode: https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=TICKET
3.3 公共类
@Component
public class WxLoginConfig {
@Value("${wx.login.appid}")
private String appId; //公众号标识
@Value("${wx.login.appsecret}")
private String appSecret; //公众号密码
@Value("${wx.login.server}")
private String server; //服务器域名地址,用于微信服务器回调。
@Value("${wx.login.qrCodeUrl}")
private String qrCodeUrl; //获取code接口
@Value("${wx.login.tokenUrl}")
private String tokenUrl; //获取token接口
@Value("${wx.login.openIdUrl}")
private String openIdUrl; //获取openid接口
@Value("${wx.login.userInfoUrl}")
private String userInfoUrl; //获取用户信息接口
@Value("${wx.login.token}")
private String token;
@Value("${wx.login.showqrcode}") //通过ticket获取二维码
private String showQrCode;
}
3.4 方式一
这种方式其实就是生一个二维码,二维码的内容是一个url。url的核心是REDIRECT_URL即回调地址。扫码之后,微信会根据REDIRECT_URL进行回调。
@Controller
@RequestMapping("/wx/login")
public class WxLoginController {
@Autowired
private WxLoginConfig wxLoginConfig;
@Autowired
private RestTemplate restTemplate;
//生成二维码
@GetMapping(value = "/qrCode")
public void getQrCode(@RequestParam(value = "isRememberMe",required = false,defaultValue = "1")String isRememberMe, @RequestParam(value = "sign") String sign, HttpServletRequest request, HttpServletResponse response) throws IOException {
String url = wxLoginConfig.getQrCodeUrl().replace("APPID",wxLoginConfig.getAppId())
.replace("REDIRECT_URL",wxLoginConfig.getServer() + "/wx/login/callback")
.replace("STATE","自定义传参");
//生成二维码的,扫描后跳转上面的REDIRECT_URL地址
QrCodeUtil.generate(url, 300, 300, "jpg", response.getOutputStream());
}
//回调
@RequestMapping(value = "/callback")
@ResponseBody
public String pcCallback(String code, String state) throws Exception {
String openId = getOpenId(code);
System.out.println(openId);
//获取微信用户信息
getUserInfo(openId);
//业务处理...
return "登录成功";
}
/**
* 获取openId
* @param code
* @return
*/
private String getOpenId(String code){
String url = wxLoginConfig.getOpenIdUrl().replace("APPID", wxLoginConfig.getAppId())
.replace("APPSECRET", wxLoginConfig.getAppSecret()).replace("CODE",code);
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
String body = responseEntity.getBody();
JSONObject object = JSONObject.parseObject(body);
return object.getString("openid");
}
/**
* 获取用户信息
* @param openId
* @return
*/
private JSONObject getUserInfo(String openId){
//从微信上中拉取用户信息
String url = wxLoginConfig.getUserInfoUrl().replace("ACCESS_TOKEN",getAccessToken()).replace("OPENID",openId);
ResponseEntity<String> forEntity = restTemplate.getForEntity(url, String.class);
String result = forEntity.getBody();
JSONObject jsonObject = JSONObject.parseObject(result);
return jsonObject;
}
}
3.5 方式二
-
先进行认证,提交
-
然后获取 access_token
-
拿到 ticket
-
生成二维码
-
扫码后,根据上图中token验证的接口地址进行回调
@Controller
@RequestMapping("/wx/login")
public class WxLoginController {
@Autowired
private WxLoginConfig wxLoginConfig;
@Autowired
private RestTemplate restTemplate;
/**
* pc点击微信登录,生成登录二维码
* @throws Exception
*/
@GetMapping(value = "/pcQrCode")
@ResponseBody
public void wxLoginPage(HttpServletRequest request, HttpServletResponse response) throws Exception {
try {
//获取token
String accessToken =getAccessToken();
//获取 ticket
String ticket = getTicket(accessToken);
//获取二维码
String qrCodeUrl = wxLoginConfig.getShowQrCode().replace("TICKET",ticket);
ResponseEntity<byte[]> forEntity = restTemplate.getForEntity(qrCodeUrl, byte[].class);
byte[] body1 = forEntity.getBody();
response.getOutputStream().write(body1);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取accessToken
* @return
*/
public String getAccessToken(){
//根据appid和appsecret获取access_token
wxLoginConfig.getTokenUrl();
String url = wxLoginConfig.getTokenUrl().replace("APPID", wxLoginConfig.getAppId()).replace("APPSECRET", wxLoginConfig.getAppSecret());
HttpHeaders headers = new HttpHeaders();
ResponseEntity<JSONObject> responseEntity = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(null, headers), JSONObject.class);
JSONObject object = responseEntity.getBody();
String accessToken = "";
accessToken = object.getString("access_token");
return accessToken ;
}
/**
* 获取ticket
* @param accessToken
* @return
*/
public String getTicket(String accessToken){
//请求地址
String getQrCodeUrl = wxLoginConfig.getQrCodeUrl().replace("TOKEN", accessToken);
HttpHeaders headers = new HttpHeaders();
//参数设置
Map<String, Object> map = new HashMap<>();
//二维码的过期时间,单位为秒,最大2592000(即30天)不填,则默认有效期为60秒。
map.put("expire_seconds", "604800");
//二维码类型,QR_SCENE为临时的整型参数值,QR_STR_SCENE为临时的字符串参数值,QR_LIMIT_SCENE为永久的整型参数值,QR_LIMIT_STR_SCENE为永久的字符串参数值
map.put("action_name", "QR_LIMIT_STR_SCENE");
Map<String, Object> innerThenMap = new HashMap<>();
//扫码回调时自定义要传输的数据
innerThenMap.put("scene_str","elwin123");
Map<String, Object> innerMap = new HashMap<>();
innerMap.put("scene",innerThenMap);
//二维码详细信息
map.put("action_info", innerMap);
// 组装请求体
HttpEntity<Map<String, Object>> sendMap =
new HttpEntity<Map<String, Object>>(map, headers);
ResponseEntity<String> responseEntity = restTemplate.postForEntity(getQrCodeUrl, sendMap, String.class);
String body = responseEntity.getBody();
JSONObject jsonObject = JSONObject.parseObject(body);
String ticket = jsonObject.getString("ticket");
return ticket;
}
@RequestMapping("/checkSign")
public String checkSign ( HttpServletRequest request) throws Exception {
//获取微信请求参数
String signature = request.getParameter("signature");
String timestamp = request.getParameter("timestamp");
String nonce = request.getParameter("nonce");
String echostr = request.getParameter ("echostr");
//参数排序。 token 就要换成自己实际写的 token
String[] params = new String[]{timestamp, nonce, "weixin"};
Arrays.sort(params);
//拼接
String paramstr = params[0] + params[1] + params[2];
//加密
//获取 shal 算法封装类
MessageDigest Sha1Dtgest = MessageDigest.getInstance("SHA-1");
//进行加密
byte[] digestResult = Sha1Dtgest.digest(paramstr.getBytes("UTF-8"));
//拿到加密结果
String mysignature = bytes2HexString(digestResult);
mysignature = mysignature.toLowerCase(Locale.ROOT);
//是否正确
boolean signsuccess = mysignature.equals(signature);
//逻辑处理
if (signsuccess && echostr != null) {
//验证签名,接入服务器
return echostr;
} else {
//接入成功后,下次回调过来就可以进行正常业务处理
return callback(request);
}
}
private String bytes2HexString(byte... bytes) {
char[] hexChars = new char[bytes.length * 2];
char[] hexArray = "0123456789ABCDEF".toCharArray();
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
/**
* 回调业务处理
* @param request
* @return
* @throws Exception
*/
private String callback(HttpServletRequest request) throws Exception{
//解析
WxMpXmlMessage message= WxMpXmlMessage.fromXml(request.getInputStream());//获取消息流,并解析xml
String messageType=message.getMsgType(); //消息类型
String messageEvent=message.getEvent(); //消息事件
String openId =message.getFromUser(); //发送者帐号
String touser=message.getToUser(); //开发者微信号
String text=message.getContent(); //文本消息 文本内容
String eventKey=message.getEventKey(); //二维码参数
if(messageType.equals("event")){
//获取微信用户信息
JSONObject userInfo = this.getUserInfo(openId);
//根据不同的回调事件处理各自的业务
switch (messageEvent){
case "SCAN": //扫码
System.out.println("扫码");
//业务处理...
return "result";
case "subscribe": //关注公众号
System.out.println("关注公众号");
//业务处理...
return "result";
case "unsubscribe": //取消关注公众号
System.out.println("取消关注公众号");
//业务处理...
return "result";
}
}
return "111";
}
/**
* 获取用户信息
* @param openId
* @return
*/
private JSONObject getUserInfo(String openId){
//从微信上中拉取用户信息
String url = wxLoginConfig.getUserInfoUrl().replace("ACCESS_TOKEN",getAccessToken()).replace("OPENID",openId);
ResponseEntity<String> forEntity = restTemplate.getForEntity(url, String.class);
String result = forEntity.getBody();
JSONObject jsonObject = JSONObject.parseObject(result);
return jsonObject;
}
}
4、参考地址:
- https://blog.csdn.net/m0_54881904/article/details/124400901
- https://blog.csdn.net/weixin_43890049/article/details/119463862#comments_22614248
- 微信公众测试平台:微信公众测试平台
- 获取Access token:获取Access token
- 生成带参数的二维码:生成带参数的二维码
5、问题
5.1 {“errcode”:40125,“errmsg”:“invalid appsecret rid: 6368b9e5-0555a81b-3c7588c4”}
检查appid和appsecret是不是配置文件没写对
5.2 redirect_uri域名与后台配置不一致,错误码10003
文章来源:https://www.toymoban.com/news/detail-604268.html
回调地址没对文章来源地址https://www.toymoban.com/news/detail-604268.html
到了这里,关于JAVA微信扫码登录的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!