微信登录的优势
目前微信用户数量巨大,用户更希望通过更快更便捷的方式进行登录,而不是传统的账号密码登录。
springboot
接入微信登陆
准备工作
网站应用微信登录是基于OAuth2.0协议标准构建的微信OAuth2.0授权登录系统。 在进行微信OAuth2.0授权登录接入之前,在微信开放平台注册开发者帐号,并拥有一个已审核通过的网站应用,并获得相应的AppID和AppSecret,申请微信登录且通过审核后,可开始接入流程。
说白了就是需要一个AppID和对应的Appsecret
传送门:微信开放平台 (qq.com)
登陆后选一个,这里是网站应用
顺便再把回调域改一下。
授权流程
那我们要做什么呢?
设置一个链接让用户跳转到微信登录扫码界面,然后用户点确认后会带上
code
和state
重定向到我们设置的回调域,这是我们带上code访问微信获得用户的一些基本信息和access_token
refresh_token
,有了token我们就可以获取用户具体的信息了。这时候我们再设置session就可以让用户登录成功了。
-
打开链接
设置一个链接,格式如下:
0. 添加回调域网址接受回调信息
在用户授权之后,将会重定向到回调域,
redirect_uri?code=CODE&state=STATE
这时我们就获取了code,随后访问链接获取 access_token
`https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code`
正确的返回:
{
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE",
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}
参数 | 说明 |
---|---|
access_token | 接口调用凭证(我们需要的) |
expires_in | access_token接口调用凭证超时时间,单位(秒),一般是两小时 |
refresh_token | 用户刷新access_token |
openid | 授权用户唯一标识,对于当前appid是唯一的 |
scope | 用户授权的作用域,使用逗号(,)分隔 |
unionid | 当且仅当该网站应用已获得该用户的userinfo授权时,才会出现该字段。 |
-
获取用户详细信息
继续访问https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID就可以获取用户的详细信息了
实际操作
1. appId和appSecret的配置
在application.yml的配置:
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@Data
@ConfigurationProperties(prefix = "wx")
public class WXConfig {
private String appId;
private String appSecret;
}
2. 设置网址
3. 设置回调域
导包
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
</dependency>
工具类
public class CommonUtil {
private static final int BUFFER_SIZE = 1024 * 8;
public static String getBody(InputStream inputStream) throws IOException {
Reader reader = new BufferedReader(new InputStreamReader(inputStream));
StringWriter writer = new StringWriter();
int read;
char[] buf = new char[BUFFER_SIZE];
while ((read = reader.read(buf)) != -1) {
writer.write(buf, 0, read);
}
return writer.getBuffer().toString();
}
}
回调域逻辑
@Slf4j
@Controller
public class WXController {
@Autowired
private WXConfig wxConfig;
@ResponseBody
@RequestMapping("/wx/login")
public String login(HttpServletRequest request) throws IOException {
String code = request.getParameter("code");
String state = request.getParameter("state");
if (code == null){
log.error("用户取消登录");
}
log.info("code = {}", code);
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
String url = "https://api.weixin.qq.com/sns/oauth2/access_token" +
"?appid=" + wxConfig.getAppId() +
"&secret=" + wxConfig.getAppSecret() +
"&code=" + code +
"&grant_type=authorization_code";
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity();
String body = CommonUtil.getBody(entity.getContent());
log.info(body);
response.close();
JSONObject bodyJson = JSON.parseObject(body);
// 这里已经获取了用户的部分信息,可以在数据库中查询,如果已经记录过了,就没有必要进入后面的步骤了
String accessToken = bodyJson.getString("access_token");
String openId = bodyJson.getString("openId");
url = "https://api.weixin.qq.com/sns/userinfo" +
"?access_token=" + accessToken +
"&openid=" + openId;
httpGet = new HttpGet(url);
response = httpClient.execute(httpGet);
body = CommonUtil.getBody(response.getEntity().getContent());
bodyJson = JSON.parseObject(body);
// 获取了用户信息后进行存储
log.info("the info of user is {}", bodyJson);
response.close();
// 登录成功,设置session
request.getSession().setAttribute("unionId", bodyJson.getString("union_id"));
return "登录成功";
}
}
\