微信文档地址
# appId
wechat.appId=wx12411231
# 密钥
wechat.appSecret=feageasgeaege
# 重定向地址,其实微信后台配置的重定向地址,可以随便改动,只要能够访问与以下配置项的域名一致即可。
# 假如你的微信后台配置的域名为:test.com, 配置文件如下配置,后面的地址为controller的路径
wechat.redirectUrl=http://test.com/api/ucenter/wx/callback
package com.song.cms.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
/**
* wx prop settings
*/
@Data
@Component
@Configuration
@ConfigurationProperties(prefix = "wechat")
public class WechatProperties {
private String appId;
private String appSecret;
private String redirectUrl;
}
@CrossOrigin
@Controller
@RequestMapping("/api/ucenter/wx")
@Slf4j
public class WxLoginController {
@Autowired
private LoginService loginService;
/**
* 生成微信二维码
*/
@GetMapping("login")
public String buildQrCode() throws UnsupportedEncodingException {
String url = loginService.buildQrCode();
return String.format("redirect:%s", url);
}
}
@Autowired
private WechatProperties wechatProperties;
/**
* 生成微信二维码
*/
@Override
public String buildQrCode() throws UnsupportedEncodingException {
String baseUrl = "https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code" +
"&scope=snsapi_login&state=%s#wechat_redirect";
String redirectUrl = URLEncoder.encode(wechatProperties.getRedirectUrl(), "utf-8");
return String.format(baseUrl, wechatProperties.getAppId(), redirectUrl, RandomStringUtils.randomAlphanumeric(6));
}
<properties>
<okhttp.version>4.4.0okhttp.version>
<gson.version>2.8.6gson.version>
properties>
<dependency>
<groupId>com.squareup.okhttp3groupId>
<artifactId>okhttpartifactId>
<version>${okhttp.version}version>
dependency>
<dependency>
<groupId>com.google.code.gsongroupId>
<artifactId>gsonartifactId>
<version>${gson.version}version>
dependency>
@CrossOrigin
@Controller
@RequestMapping("/api/ucenter/wx")
@Slf4j
public class WxLoginController {
@Autowired
private LoginService loginService;
/**
* 回调地址
*/
@GetMapping("/callback")
public String callback(String code, String state, HttpServletRequest request, Model model) throws Exception {
log.info("================== 微信回调执行,传入参数: code: {}, state: {} ==========================", code, state);
SongResult result = loginService.callback(code, state, request);
if (!result.isSuccess()) {
throw new Exception(result.getMessage());
}
return "redirect:http://localhost:3000?token=" + result.getData();
}
}
package com.song.cms.entity;
import lombok.Data;
@Data
public class WechatTokenInfo {
private String access_token;
private String openid;
// 唯一标识
private String unionid;
private String nickname;
private String headimgurl;
private Integer sex;
}
package com.song.common;
import org.springframework.http.HttpStatus;
import java.util.HashMap;
public class SongResult extends HashMap<String, Object> {
public void code(HttpStatus status) {
this.put("code", status.value());
}
public SongResult message(String message) {
this.put("message", message);
return this;
}
public SongResult data(Object data) {
this.put("data", data);
return this;
}
public SongResult success() {
this.code(HttpStatus.OK);
this.message("操作成功!");
return this;
}
public SongResult fail() {
this.code(HttpStatus.INTERNAL_SERVER_ERROR);
this.message("操作失败!");
return this;
}
public SongResult notFound() {
this.code(HttpStatus.NOT_FOUND);
this.message("您访问的数据不存在!");
return this;
}
@Override
public SongResult put(String key, Object value) {
super.put(key, value);
return this;
}
/**
* 校验是否OK
*/
public boolean isSuccess() {
return (int) this.get("code") == HttpStatus.OK.value();
}
/**
* 获得消息
*/
public String getMessage() {
return (String) this.get("message");
}
/**
* 获得数据
*/
public Object getData() {
return this.get("data");
}
}
/**
* wx回调接口地址
*
* @param code code
* @param state state
* @param request request
*/
@Override
public SongResult callback(String code, String state, HttpServletRequest request) throws IOException {
SongResult result = new SongResult();
// 获得access_token
String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
String accessTokenUrl = String.format(url, wechatProperties.getAppId(), wechatProperties.getAppSecret(), code);
OkHttpClient client = new OkHttpClient();
Request req = new Request.Builder().url(accessTokenUrl).build();
Response response = client.newCall(req).execute();
if (!response.isSuccessful()) {
log.error(" ======== 获取微信access_token响应失败! ========");
return result.fail().message("登录失败");
}
// 获得微信用户token
String tokenInfo = Objects.requireNonNull(response.body()).string();
Gson gson = new Gson();
WechatTokenInfo wechatTokenInfo = gson.fromJson(tokenInfo, WechatTokenInfo.class);
String token = wechatTokenInfo.getAccess_token();
if (StringUtils.isBlank(token)) {
log.error(" ======== 获取微信access_token失败! access_token: {} ========", token);
return result.fail().message("授权认证失败");
}
// 获得微信用户信息
WechatTokenInfo wxUserInfo = getWxUserInfo(token, wechatTokenInfo.getOpenid());
if (wxUserInfo == null) {
log.error(" ======== 获取微信用户基本信息失败! token:{}. openid: {} ========", token, wechatTokenInfo.getOpenid());
return result.fail().message("授权认证失败");
}
User dbUser = userService.getUserByWxUnionid(wxUserInfo.getUnionid());
// 用户为空, 指引用户绑定手机号
if (dbUser == null) {
log.info(" ======== 【用户扫码登录】微信号尚未绑定,执行微信注册逻辑! 微信号: {}, ======== ", wxUserInfo.getUnionid());
dbUser = new User();
dbUser.setAvatar(wxUserInfo.getHeadimgurl());
dbUser.setNickName(wxUserInfo.getNickname());
dbUser.setSex(wxUserInfo.getSex());
dbUser.setWxUnionid(wxUserInfo.getUnionid());
dbUser.setDescription("注册用户");
userService.save(dbUser);
}
dbUser.setLastLoginTime(LocalDateTime.now());
userService.updateById(dbUser);
//使用jwt根据member对象生成token字符串
String jwtToken = JwtUtils.getJwtToken(String.valueOf(dbUser.getId()), dbUser.getNickName());
return result.success().data(jwtToken);
}
/**
* 获得微信用户信息
*
* @param token 微信 token
* @param openid 微信 openid
* @return WechatTokenInfo
*/
public WechatTokenInfo getWxUserInfo(String token, String openid) {
WechatTokenInfo wechatTokenInfo = null;
String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s";
String userInfoUrl = String.format(baseUserInfoUrl, token, openid);
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(userInfoUrl).build();
try {
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
String userInfo = Objects.requireNonNull(response.body()).string();
Gson gson = new Gson();
wechatTokenInfo = gson.fromJson(userInfo, WechatTokenInfo.class);
}
log.error(" ======== 获取微信用户基本信息: {} ========", wechatTokenInfo);
} catch (Exception e) {
log.error("获得微信用户基本信息失败! {}", e.getMessage());
}
return wechatTokenInfo;
}