微信扫码登录大体上有两种实现方式:
注意:
这两个平台的扫码登录一定要区分开,这两者授权登录是不一样的。
下面我们使用基于微信公众平台的扫码登录。
查看官方文档:https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Getting_Started_Guide.html
由于我是个人开发者,注册申请一个微信公众平台的测试号就可以了。
微信公众平台接口测试帐号申请:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
使用微信扫码登录后,就可以拿到 appID 和 appsecret。
我们可以在微信公众平台接口调试工具
(https://mp.weixin.qq.com/debug/) 中使用测试接口。
例如:获取access_token
在“网页服务”中找到“网页账号”,修改“网页授权获取用户基本信息”接口的回调域名。
注意:
接下来就可以开发了。
微信授权登录的官方文档:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
1)页面授权流程相关接口如下:
2)我们PC端使用微信扫码登陆的设计思路
注意:
为了方便,我们关注PC后端业务实现,简化上面设计思路,将 redirect_uri 直接指向 后端获取微信用户接口。
创建 springboot项目,引入依赖。
<dependency>
<groupId>org.apache.httpcomponentsgroupId>
<artifactId>httpclientartifactId>
<version>4.5.12version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.76version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.22version>
dependency>
@RestController
public class WeiXinPublicAccountController {
@Autowired
private WinXinPublicAccountService winXinPublicAccountService;
/**
* 获取授权url接口
*/
@RequestMapping("/getAuthUrl")
public String getAuthUrl(HttpSession session) throws Exception {
// 用于第三方应用防止CSRF攻击
String uuid = UUID.randomUUID().toString().replaceAll("-", "");
// 临时放到session。开发是放到Redis
session.setAttribute("state", uuid);
return winXinPublicAccountService.getAuthUrl(uuid);
}
/**
* 授权回调接口
*/
@GetMapping(value = "/callback")
public String callback(HttpServletRequest request) throws Exception {
HttpSession session = request.getSession();
// 得到Authorization Code
String code = request.getParameter("code");
// 我们放在地址中的状态码
String state = request.getParameter("state");
String uuid = (String) session.getAttribute("state");
// 验证我们发送的状态码
//if(uuid == null || !uuid.equals(state)){
// return "参数为空或者状态码已过期,状态码不正确" ;
//}
// 建立微信用户和PC端用户的绑定关系
String accessToken = winXinPublicAccountService.getAccessToken(code);
/**
* TODO 将state与微信用户openid建立关联,放到Redis
*/
return accessToken;
}
/**
* 微信登录接口(轮询)
*/
@GetMapping(value = "/weixinLogin")
public String weixinLogin(HttpServletRequest request) throws Exception {
HttpSession session = request.getSession();
// 我们放在地址中的状态码
String state = request.getParameter("state");
String uuid = (String) session.getAttribute("state");
// 验证我们发送的状态码
//if(uuid == null || !uuid.equals(state)){
// return "参数为空或者状态码已过期,状态码不正确" ;
//}
/**
* 1、TODO 通过state获取微信用户openid,从而获取都PC端用户信息
* 2、TODO 通过PC端用户信息登录并保存到Session,最后返回登录后的信息, 即与我们通过账号登录校验用户信息之后的的登录逻辑同理。
*/
return "微信扫码登录成功";
}
}
@Service
public class WinXinPublicAccountService {
/**
* 公众平台提供的 appid 和 appsecret
*/
public String APPID = "wx2a8f0xxx";
public String APPSECRET = "afd4b135xxxxxxxxx";
/**
* 我们自定义认证重定向url
*/
public static final String AUTH_REDIRECT_URI = "http://qy7cbq.natappfree.cc/weixin/callback";
public String getAuthUrl(String state){
// 获取用户认证授权URL,来获取Authorization Code
String oauthUrl = WeiXinConstant.AUTH_URL
.replace(WeiXinConstant.APPID, APPID)
.replace(WeiXinConstant.REDIRECT_URI, URLEncoder.encode(AUTH_REDIRECT_URI, StandardCharsets.UTF_8))
.replace(WeiXinConstant.SCOPE, WeiXinConstant.SNSAPI_USERINFO)
.replace(WeiXinConstant.STATE, state);
System.out.println(oauthUrl);
return oauthUrl;
}
public String getAccessToken(String code){
//通过Code获取Access Token
String getAccessTokenUrl = WeiXinConstant.GET_USER_ACCESS_TOKEN_URL
.replace(WeiXinConstant.APPID, APPID)
.replace(WeiXinConstant.SECRET, APPSECRET)
.replace(WeiXinConstant.CODE, code);
JSONObject resJson = null;
try {
resJson = HttpRequestUtils.httpRequestGet(getAccessTokenUrl);
} catch (IOException e) {
System.out.println("获取 accessToken 异常, e=" + e);
return "获取 accessToken 异常";
}
System.out.println("获取 access_token接口成功,resJson=" + resJson);
String accessToken = resJson.getString("access_token");
String openId = resJson.getString("openid");
if (StringUtils.isBlank(accessToken) || StringUtils.isBlank(openId)) {
return "获取 accessToken 为空";
}
//测试获取用户信息
getUserInfo(accessToken, openId);
return resJson.toString();
}
public String getUserInfo(String accessToken, String openId){
// 根据openid和 access_token获取用户信息
String getUserInfoUrl = WeiXinConstant.GET_USER_INFO_URL
.replace(WeiXinConstant.ACCESS_TOKEN, accessToken)
.replace(WeiXinConstant.OPENID, openId);
JSONObject resJson = null;
try {
resJson = HttpRequestUtils.httpRequestGet(getUserInfoUrl);
} catch (IOException e) {
System.out.println("获取 UserInfo 异常, e=" + e);
return "获取 UserInfo 异常";
}
System.out.println("获取 UserInfo 接口成功,resJson=" + resJson);
/**
* TODO 这时就该写自己的业务逻辑了
*/
return resJson.toString();
}
}
微信平台常量类:
/**
* 微信平台常量
*/
public class WeiXinConstant {
/**
* 公众号-服务号URL
*/
public static String APPID = "APPID";
public static String SECRET = "SECRET";
public static String REDIRECT_URI = "REDIRECT_URI";
public static String SCOPE = "SCOPE";
public static String STATE = "STATE";
public static String CODE = "CODE";
public static String ACCESS_TOKEN = "ACCESS_TOKEN";
public static String OPENID = "OPENID";
public static String SNSAPI_BASE = "snsapi_base";
public static String SNSAPI_USERINFO = "snsapi_userinfo";
/**
* 获取用户认证授权URL
*/
public static final String AUTH_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect";
/**
* 获取用户access_token和openid信息URL
*/
public static final String GET_USER_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
/**
* 根据openid和 access_token获取用户信息URL
*/
public static final String GET_USER_INFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
}
HttpRequestUtils工具类:
public class HttpRequestUtils {
/**
* GET 请求
*/
public static JSONObject httpRequestGet(String url) throws IOException {
CloseableHttpClient client = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(url);
HttpResponse response = client.execute(httpGet);
HttpEntity entity = response.getEntity();
if (entity != null) {
String result = EntityUtils.toString(entity, "UTF-8");
return JSONObject.parseObject(result);
}
httpGet.releaseConnection();
return null;
}
}
启动项目.
1)获取二维码,这里通过工具展示。
2)用户扫码登录ok。
3)轮询的登录接口,此时应该响应ok。
到此,基于公众号扫码授权登录就搞定了。
根据设计思路,实现代码比较简陋,实际开发中可根据需求做响应调整。
– 求知若饥,虚心若愚。