准备工作
微信开放平台进行开发者资质认证(只有企业才能认证),然后得到 appid
和app_secret
,然后配置’redirect_url’也就是扫码成功后跳转的地址
开始
根据上面的appid等信息跳转扫码页面,返回一个 code
类似于验证码,根据 code 访问另一个固定地址获取openid
和accsess_token
,然后再根据 openid和access_token 访问另一个固定地址获取用户信息
1. 将上面的信息配置到 application.yml
wx:
open:
appid: 你的appid # 微信开放平台 appid
appsecret: 你的appsecret # 微信开放平台 appsecret
redirecturl: 重定向url # 微信开放平台 重定向url(需要在微信开放平台配置)
2. 为了方便管理,创建一个常量类
@Component
public class ConstantProperties implements InitializingBean {
@Value("${wx.open.appid}")
private String appId;
@Value("${wx.open.appsecret}")
private String appSecret;
@Value("${wx.open.redirecturl}")
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;
}
}
3. 编写接口
因为要跳转到微信扫码的界面,所以必须标记 @Controller 而不是 @RestController
3.1 二维码页面
@GetMapping("login")
public String genQrConnect() {
// 微信开放平台授权baseUrl,固定的地址
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 = ConstantPropertiesUtil.WX_OPEN_REDIRECT_URL; //获取业务服务器重定向地址
try {
redirectUrl = URLEncoder.encode(redirectUrl, "UTF-8"); //url编码
} catch (UnsupportedEncodingException e) {
throw new GolbalException( e.getMessage());
}
// 防止csrf攻击(跨站请求伪造攻击)
String state = UUID.randomUUID().toString().replaceAll("-", "");//一般情况下会使用一个随机数
//生成qrcodeUrl
String qrcodeUrl = String.format(
baseUrl,
ConstantPropertiesUtil.WX_OPEN_APP_ID,
redirectUrl,
state);
return "redirect:" + qrcodeUrl;
}
3.2 扫码成功后的 callback接口(登录逻辑在这里实现)
@GetMapping("/callback")
public String callback(String code,String state){
// 获取code值,拿着 code 请求微信固定地址,得到 accsess_token 和 openId
String baseAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token" +
"?appid=%s" +
"&secret=%s" +
"&code=%s" +
"&grant_type=authorization_code";
String accessTokenUrl = String.format(baseAccessTokenUrl,
ConstantPropertiesUtil.WX_OPEN_APP_ID,
ConstantPropertiesUtil.WX_OPEN_APP_SECRET,
code);
String result = restTemplate.getForObject(accessTokenUrl,String.class);
HashMap<String,String> hashMap = JSON.parseObject(result, HashMap.class);
String accessToken = hashMap.get("access_token");
String openid = hashMap.get("openid");
log.info("token:{},openid:{}",accessToken,openid);
// 查询数据库当前用用户是否曾经使用过微信登录
User user = userService.getByOpenId(openid);
if (user == null){
log.info("新用户注册");
//访问微信的资源服务器,获取用户信息
String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
"?access_token=%s" +
"&openid=%s";
String userInfoUrl = String.format(baseUserInfoUrl, accessToken, openid);
String resultUserInfo = null;
resultUserInfo = restTemplate.getForObject(userInfoUrl,String.class);
log.info("用户信息:{}",resultUserInfo);
//解析json
HashMap<String,Object> mapUserInfo = JSON.parseObject(resultUserInfo, HashMap.class);
// 获取微信名
String nickname = (String)mapUserInfo.get("nickname");
// 获取头像
String headimgurl = (String)mapUserInfo.get("headimgurl");
//向数据库中插入一条记录
user = new User();
user.setNickname(nickname);
user.setOpenid(openid);
user.setAvatar(headimgurl);
userService.save(member);
}
// @TODO 登录逻辑,生成token等
return "redirect:http://localhost:3000";
}