微信扫码登录
微信分为三个平台:
微信公众平台: 订阅号、服务号、企业号以及小程序给我们提供的服务
微信商户平台: 在这个商户平台不仅提供开发者有关的开发文档,而且提供流水记录和红包等相关的运营策略,所以这里是开发者,运营者,财务的领地!所有使用微信支付,不论是扫码支付,app支付等所有的流水订单都可以在这里找到足迹,为我们的每一笔订单提供对账凭证和查询记录
微信开放平台: 开发者在公众平台网站中创建公众号、获取接口权限后,可以通过阅读本接口文档来帮助开发
网站应用微信登录开发指南
网站应用微信登录是基于OAuth2.0协议标准构建的微信OAuth2.0授权登录系统。
在进行微信OAuth2.在进行微信OAuth2.0授权登录接入之前,在微信开放平台注册开发者帐号,并拥有一个已审核通过的网站应用,并获得相应的AppID和AppSecret,申请微信登录且通过审核后,可开始接入流程。
授权流程说明
微信OAuth2.0授权登录让微信用户使用微信身份安全登录第三方应用或网站,在微信用户授权登录已接入微信OAuth2.0的第三方应用后,第三方可以获取到用户的接口调用凭证(access_token),通过access_token可以进行微信开放平台授权关系接口调用,从而可实现获取微信用户基本开放信息和帮助用户实现基础开放功能等。
微信OAuth2.0授权登录目前支持authorization_code模式,适用于拥有server端的应用授权。该模式整体流程为:
1. 第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据code参数;
2. 通过code参数加上AppID和AppSecret等,通过API换取access_token;
3. 通过access_token进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。
获取access_token时序图:

第一步:请求CODE
第三方使用网站应用授权登录前请注意已获取相应网页授权作用域(scope=snsapi_login),则可以通过在PC端打开以下链接:
https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
若提示“该链接无法访问”,请检查参数是否填写错误,如redirect_uri的域名与审核时填写的授权域名不一致或scope不为snsapi_login。
参数说明
| 参数 | 是否必须 | 说明 |
|---|---|---|
| appid | 是 | 应用唯一标识 |
| redirect_uri | 是 | 请使用urlEncode对链接进行处理 |
| response_type | 是 | 填code |
| scope | 是 | 应用授权作用域,拥有多个作用域用逗号(,)分隔,网页应用目前仅填写snsapi_login即 |
| state | 否 | 用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验 |
第一步配置微信扫码登录相关参数,在springboot的yml配置文件中声明
wechat:
appId: 自己的数据
appSecret: 自己申请的数据
returnURI: http://自己申请配置的域名/后台的collection的上下文路径
返回说明
用户允许授权后,将会重定向到redirect_uri的网址上,并且带上code和state参数
redirect_uri?code=CODE&state=STATE
若用户禁止授权,则重定向后不会带上code参数,仅会带上state参数
redirect_uri?state=STATE
第二步建一个微信的config配置类,来引入微信的相关数据
@Component
@ConfigurationProperties(prefix = "wechat")
public class WeChatConfig {
private String appId;
private String appSecret;
private String returnUri;
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getAppSecret() {
return appSecret;
}
public void setAppSecret(String appSecret) {
this.appSecret = appSecret;
}
public String getReturnUri() {
return returnUri;
}
public void setReturnUri(String returnUri) {
this.returnUri = returnUri;
}
}
第三步配置controller层
@Controller
@RequestMapping("/WeChat")
public class WeChatController {
@Autowired
WeChatConfig weChatConfig;
@RequestMapping("/login")
public String login(HttpServletResponse response) {
/**1.构造生成微信登录二维码所需要的参数
* https://open.weixin.qq.com/connect/qrconnect?
* appid=APPID&redirect_uri=REDIRECT_URI&response_type=code
* &scope=SCOPE&state=STATE#wechat_redirect
*/
StringBuilder getCodeUrl = new StringBuilder("https://open.weixin.qq.com/connect/qrconnect?");
try {
getCodeUrl.append("appid=").append(weChatConfig.getAppId()).append("&")
.append("redirect_uri=").append(URLEncoder.encode(weChatConfig.getReturnURI(),"UTF-8")).append("&")
.append("response_type=code").append("&")
.append("scope=snsapi_login").append("&")
.append("state=STATE#wechat_redirect");
} catch (Exception e) {
e.printStackTrace();
}
//2.对生成二维码连接发出HTTP请求
//如果APPID,redirectURI正确那么微信平台就会重定向到 redirect_uri?code=CODE&state=STATE
return "redirect:"+getCodeUrl.toString();
}
第四步接收微信返回的临时code,如果用户通过授权,那么信平台正常返回,会有一个access_token,那么就代表授权成功,可以获取用户的基本信息(头像,昵称...)
这里可以看授权后接口调用(UnionID)https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316518&token=&lang=zh_CN
获取用户个人信息(UnionID机制)
接口说明
此接口用于获取用户个人信息。开发者可通过OpenID来获取用户基本信息。特别需要注意的是,如果开发者拥有多个移动应用、网站应用和公众帐号,可通过获取用户基本信息中的unionid来区分用户的唯一性,因为只要是同一个微信开放平台帐号下的移动应用、网站应用和公众帐号,用户的unionid是唯一的。换句话说,同一用户,对同一个微信开放平台下的不同应用,unionid是相同的。请注意,在用户修改微信头像后,旧的微信头像URL将会失效,因此开发者应该自己在获取用户信息后,将头像图片保存下来,避免微信头像URL失效后的异常情况。
请求说明
http请求方式: GET
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
参数说明
| 参数 | 是否必须 | 说明 |
|---|---|---|
| access_token | 是 | 调用凭证 |
| openid | 是 | 普通用户的标识,对当前开发者帐号唯一 |
| lang | 否 | 国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语,默认为zh-CN |
返回说明
正确的Json返回结果:
{
"openid":"OPENID",
"nickname":"NICKNAME",
"sex":1,
"province":"PROVINCE",
"city":"CITY",
"country":"COUNTRY",
"headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
"privilege":[
"PRIVILEGE1",
"PRIVILEGE2"
],
"unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
}
| 参数 | 说明 |
|---|---|
| openid | 普通用户的标识,对当前开发者帐号唯一 |
| nickname | 普通用户昵称 |
| sex | 普通用户性别,1为男性,2为女性 |
| province | 普通用户个人资料填写的省份 |
| city | 普通用户个人资料填写的城市 |
| country | 国家,如中国为CN |
| headimgurl | 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空 |
| privilege | 用户特权信息,json数组,如微信沃卡用户为(chinaunicom) |
| unionid | 用户统一标识。针对一个微信开放平台帐号下的应用,同一用户的unionid是唯一的。 |
建议:
开发者最好保存用户unionID信息,以便以后在不同应用中进行用户信息互通。
错误的Json返回示例:
{
"errcode":40003,"errmsg":"invalid openid"
}
下面是代码内容
@RequestMapping("/callback")
public String callback(String code, Model model) {
//System.out.println("code="+code);//当微信用户授权之后,微信会对配置redirectURI发出请求:http://freedom.s1.natapp.cc/WeChat/callback?code=CODE&state=STATE
//微信会携带code参数,我们下面用这个code
//1.发出HTTP请求,携带code参数,最终从响应中获取access_token
//https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
StringBuilder getAccessTokenUrl = new StringBuilder("https://api.weixin.qq.com/sns/oauth2/access_token?");
getAccessTokenUrl.append("appid=").append(weChatConfig.getAppId()).append("&")
.append("secret=").append(weChatConfig.getAppSecret()).append("&")
.append("code=").append(code).append("&")
.append("grant_type=authorization_code");
String responseJson = UrlUtils.loadURL(getAccessTokenUrl.toString());
Map<String,String> responseParams = JSONObject.parseObject(responseJson, Map.class);
//2.通过换取的access_token以及opendid来获取用户的基本信息
//https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
StringBuilder getUserInfoUrl = new StringBuilder("https://api.weixin.qq.com/sns/userinfo?");
getUserInfoUrl.append("access_token=").append(responseParams.get("access_token")).append("&")
.append("openid=").append(responseParams.get("openid"));
String userJson = UrlUtils.loadURL(getUserInfoUrl.toString());
Map<String,String> map = JSONObject.parseObject(userJson, Map.class);
return "redirect:/index.html";
}
还有一个UrlUtils的工具类类
/**
* 本类提供了对URL所指向的内容的加载操作
* @author hduser
*
*/
public class UrlUtils {
/**
* 获取url网址返回的数据内容
* @param urlStr
* @return
*/
public static String loadURL(String urlStr){
try{
URL url = new URL(urlStr);
HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
InputStream inputStream = urlConnection.getInputStream();
String responseStr = ConvertToString(inputStream);
return responseStr;
}catch(IOException e){
e.printStackTrace();
return null;
}
}
private static String ConvertToString(InputStream inputStream){
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
StringBuilder result = new StringBuilder();
String line = null;
try {
while((line = bufferedReader.readLine()) != null){
result.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try{
inputStreamReader.close();
inputStream.close();
bufferedReader.close();
}catch(IOException e){
e.printStackTrace();
}
}
return result.toString();
}
}
3495



被折叠的 条评论
为什么被折叠?



