Spring boot实现微信登录
注:本文来自:B站尚硅谷尚医通项目总结
一、登录流程
1、扫码后跳转流程
2、获取扫描人信息
二、流程分析
微信官方档案:
https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html
总体分析:
第一步:请求code(生成授权URL)
第二步:通过code获取access_token(开发回调URL)
官网总体流程分析:
1. 第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据code参数;
2. 通过code参数加上AppID和AppSecret等,通过API换取access_token;
3. 通过access_token进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。
1、前端获取微信登录二维码,调用后端接口,获取微信登录生成二维码需要的参数
参数 | 是否必须 | 说明 |
---|---|---|
appid | 是 | 应用唯一标识 |
redirect_uri | 是 | 请使用urlEncode对链接进行处理 |
response_type | 是 | 填code |
scope | 是 | 应用授权作用域,拥有多个作用域用逗号(,)分隔,网页应用目前仅填写snsapi_login |
state | 否 | 用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验 |
返回说明
用户允许授权后,将会重定向到redirect_uri的网址上,并且带上code和state参数
redirect_uri?code=CODE&state=STATE
2、后点击登录,调用后台微信登录回调接口方法
说明:由于在本地测试,调用微信后台的回调地址,设置重定向到本地方法
3、获取微信回调接口的code,带着code,加上appid,appsecret,去请求微信官方固定地址,获取access_token
4、通过返回access_token字符串后,获取access_token的值和openid的值(微信唯一id)
5、判断数据库是否存在微信的扫描人信息,根据openid判断
6、没有则进行注册,带上access_token,openid去请求微信固定地址,获取扫描人信息,解析用户信息,添加进数据库
7、存在openid,进行登录,返回name和token字符串
8、最后带着token信息,重定向到登录成功首页
/**
* 获取微信登录生成二维码需要的参数
* @return
*/
@ApiOperation(value = "获取微信登录生成二维码需要的参数")
@GetMapping("/getLoginParam")
@ResponseBody
public Result genQrConnect(){
try {
String redirectUri = URLEncoder.encode(ConstantWxPropertiesUtil.WX_OPEN_REDIRECT_URL,"UTF-8");
HashMap<String, Object> map = new HashMap<>();
map.put("appid", ConstantWxPropertiesUtil.WX_OPEN_APP_ID);
map.put("scope","snsapi_login");
map.put("redirectUri",redirectUri);
map.put("state",System.currentTimeMillis()+"");
return Result.ok(map);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return Result.fail(ResultCodeEnum.DATA_ERROR);
}
}
/**
* 微信登录回调接口方法
* @param code
* @param state
* @return 返回重定向的地址
*/
@RequestMapping("/callback")
public String callback(String code, String state) {
String redirectUrl = userInfoService.wxLogin(code,state);
return "redirect:"+redirectUrl;
}
/**
* 微信登录
* @param code
* @param state
* @return
*/
@Override
public String wxLogin(String code, String state) {
//1、获取微信回调接口的code
System.out.println("code=:"+code);
//2、带着code,加上appid,appsecret,去请求微信官方固定地址,获取access_token
StringBuffer baseAccessTokenUrl = new StringBuffer()
.append("https://api.weixin.qq.com/sns/oauth2/access_token")
.append("?appid=%s")
.append("&secret=%s")
.append("&code=%s")
.append("&grant_type=authorization_code");
String accessTokenUrl = String.format(baseAccessTokenUrl.toString(),
ConstantWxPropertiesUtil.WX_OPEN_APP_ID,
ConstantWxPropertiesUtil.WX_OPEN_APP_SECRET,
code);
try {
//2.1、请求Url
String accessTokenInfo = HttpClientUtils.get(accessTokenUrl, "utf-8");
System.out.println(accessTokenInfo);
//3、通过返回access_token字符串后,获取access_token的值和openid的值(微信唯一id)
JSONObject jsonObject = JSONObject.parseObject(accessTokenInfo);
String access_token = jsonObject.getString("access_token");
String openid = jsonObject.getString("openid");
//4、判断数据库是否存在微信的扫描人信息,根据openid判断
UserInfo userInfo = baseMapper.selectOne(new QueryWrapper<UserInfo>().eq("openid", openid));
if(userInfo == null){
//4.1、没有则进行注册,带上access_token,openid去请求微信固定地址,获取扫描人信息
String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
"?access_token=%s" +
"&openid=%s";
String userInfoUrl = String.format(baseUserInfoUrl.toString(), access_token, openid);
String resultInfo = HttpClientUtils.get(userInfoUrl);
JSONObject jsonUser = JSONObject.parseObject(resultInfo);
//解析用户信息
//用户昵称
String nickname = jsonUser.getString("nickname");
//用户头像
String headimgurl = jsonUser.getString("headimgurl");
//4.2、获取到扫描人信息,添加进数据库
userInfo = new UserInfo();
userInfo.setNickName(nickname);
userInfo.setOpenid(openid);
userInfo.setStatus(1);
int insert = baseMapper.insert(userInfo);
}
//5、存在openid,进行登录,返回name和token字符串
Map<String,String> map = new HashMap<>();
String name = userInfo.getName();
if(StringUtils.isEmpty(name)) {
name = userInfo.getNickName();
}
if(StringUtils.isEmpty(name)) {
name = userInfo.getPhone();
}
map.put("name", name);
//6、
//判断userInfo是否有手机号,如果手机号为空,返回openid
//如果手机号不为空,返回openid值是空字符串
//前端判断:如果openid不为空,绑定手机号,如果openid为空,不需要绑定手机号
/**
* 阿里云短信服务现在个人无法开通,手机登录未完成,则始终让openid为空,不进行手机号绑定
*/
//TODO 手机验证
if(StringUtils.isEmpty(userInfo.getNickName())) {
map.put("openid", userInfo.getOpenid());
} else {
map.put("openid", "");
}
//7、使用jwt生成token字符串
String token = JwtHelper.createToken(userInfo.getId(), name);
map.put("token",token);
//8、跳转到前端页面,登录成功
String redirectUrl = ConstantWxPropertiesUtil.YYGH_BASE_URL + "/weixin/callback?token="+map.get("token")+ "&openid="+map.get("openid")+"&name="+ URLEncoder.encode(map.get("name"),"utf-8");
return redirectUrl;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}