1. 微信登录的两种实现方式
第一种是基于微信公众号进行登录, 第二种是基于微信开放平台进行登录.
原因是微信登录不同于 QQ 登录和微博登录, 微信登录没有提供输入账密码登录功能. 微信只提供了扫码登录功能, 如果是 PC 端进行登录的话可以用手机进行扫码, 但是如果是手机端打开二维码是不能进行扫码的, 即便是长按二维码识别功能, 但是非常不友好.
2. 微信登录的实现方式也有两种
第一种是没有自己的账号体系, 直接拉取微信用户信息来进行网站登录.
第二种是有自己的账号体系, 授权成功后需要绑定自己的账号.
两种实现方式都可以, 只是在向 session 中存用户信息的时候是存用户获取的微信信息还是根据获取的微信信息 (可以根据 openID 和 nickname 进行对应查询用户) 转换为自己系统内对应的账户信息.
3. 基于微信公众号进行授权登录
1. 简介
如果用户在微信客户端中访问第三方网页, 公众号可以通过微信网页授权机制, 来获取用户基本信息, 进而实现业务逻辑.
总的来说, 分为四部:
1, 引导用户进入授权页面同意授权, 获取 code
2, 通过 code 换取网页授权 access_token(与基础支持中的 access_token 不同)
3, 如果需要, 开发者可以刷新网页授权 access_token, 避免过期
4, 通过网页授权 access_token 和 openid 获取用户基本信息(支持 UnionID 机制)
2. 进行授权
利用授权的微信公众号(如果没有可以用开发者工具的微信公众号测试账号).
1. 到接口设置修改域名
2. 逻辑分析(刷新 access_token 暂时不考虑)
第一步: 用户同意授权, 获取 code
接口地址如下:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
尤其注意: 由于授权操作安全等级较高, 所以在发起授权请求时, 微信会对授权链接做正则强匹配校验, 如果链接的参数顺序不对, 授权页面将无法正常访问
参数说明如下:
下图为 scope 等于 snsapi_userinfo 时的授权页面:
如果用户同意授权, 页面将跳转至 redirect_uri/?code=CODE&state=STATE.
code 说明 : code 作为换取 access_token 的票据, 每次用户授权带上的 code 将不一样, code 只能使用一次, 5 分钟未被使用自动过期.
第二步: 通过 code 换取网页授权 access_token
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
请注意, 这里通过 code 换取的是一个特殊的网页授权 access_token, 与基础支持 (素材管理等操作) 中的 access_token(该 access_token 用于调用其他接口)不同.
第三步: 拉取用户信息(需 scope 为 snsapi_userinfo)
如果网页授权作用域为 snsapi_userinfo, 则此时开发者可以通过 access_token 和 openid 拉取用户信息了.
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
参数 | 描述 |
---|---|
access_token | 网页授权接口调用凭证, 注意:此 access_token 与基础支持的 access_token 不同 |
openid | 用户的唯一标识 |
lang | 返回国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语 |
3. 代码实现
WeixinAuthController 代码
- package cn.qlq.controller.weixin;
- import java.io.UnsupportedEncodingException;
- import java.NET.URLEncoder;
- import org.apache.commons.lang3.StringUtils;
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.Web.bind.annotation.ResponseBody;
- import com.alibaba.fastjson.JSONObject;
- import cn.qlq.utils.HttpUtils;
- import cn.qlq.utils.weixin.WeixinConstants;
- @Controller
- @RequestMapping("weixin/auth")
- public class WeixinAuthController {
- /**
- * 首页, 跳转到 index.html,index.HTML 有一个连接会访问下面的 login 方法
- *
- * @return
- */
- @RequestMapping("/index")
- public String index() {
- return "weixinauth/index";
- }
- /**
- * (一)微信授权: 重定向到授权页面
- *
- * @return
- * @throws UnsupportedEncodingException
- */
- @RequestMapping("/login")
- public String authorize() throws UnsupportedEncodingException {
- // 回调地址必须在公网可以访问
- String recirectUrl = URLEncoder.encode("http://6965ee39.ngrok.io/weixin/auth/calback.html", "UTF-8");
- // 授权地址
- String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";
- url = url.replace("APPID", WeixinConstants.APPID).replace("REDIRECT_URI", recirectUrl);
- // 参数替换之后重定向到授权地址
- return "redirect:" + url;
- }
- /**
- * (二)用户同意授权; (三)微信会自动重定向到配置的 URL 并由 SpringMVC 分配到该方法并携带参数 code 和 state 用于换取 access_token 和 openid;
- * (四) 用 access_token 和 openid 获取用户信息 (五) 如果有必要可以进行登录, 两种: 第一种是直接拿微信号登录; 第二种是根据 openid 和 nickname 获取账号进行登录
- *
- * @param code
- * @param state
- * @return
- * @throws UnsupportedEncodingException
- */
- @RequestMapping("/calback")
- @ResponseBody
- public String calback(String code, String state) throws UnsupportedEncodingException {
- // 获取 access_token 和 openid
- String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
- url = url.replace("APPID", WeixinConstants.APPID).replace("SECRET", WeixinConstants.APP_SECRET).replace("CODE",
- code);
- String doGet = HttpUtils.doGet(url, null);
- if (StringUtils.isNotBlank(doGet)) {
- JSONObject parseObject = JSONObject.parseObject(doGet);
- System.out.println(parseObject);
- // 获取两个参数之后获取用户信息
- String accessToken = parseObject.getString("access_token");
- String openid = parseObject.getString("openid");
- String getUserInfoURL = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
- getUserInfoURL = getUserInfoURL.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openid);
- String doGet2 = HttpUtils.doGet(getUserInfoURL, null);
- // 可以用获取到的用户信息进行两种方式的登录
- System.out.println(doGet2);
- return doGet2;
- }
- return "";
- }
- }
- index.HTML:
- <!doctype HTML>
- <HTML>
- <head>
- <meta http-equiv="Content-Type" contexnt="text/html; charset=UTF-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0"
- />
- </head>
- <body style="font-size: 40px; text-align: center;">
- <a href="/weixin/auth/login.html">
- 微信授权登录
- </a>
- </body>
- </HTML>
解释:<meta name="viewport" content="width=device-width, initial-scale=1.0" /> 是让页面自适应手机宽度.
测试:
(1)从 PC 端访问页面如下:
到主页
点击微信授权登录:
(2)手机端微信内打开如下:(手机自带的浏览器打开效果同上面)
到主页:
点击微信授权登录:
4. 基于微信开放平台进行登录
微信公众平台主要为公众号服务, 主要用于微信公众号二次开发; 微信开放平台支持 Web 应用, 移动应该, 公众号整合等.
到微信开放平台注册账号之后并认证之后创建应用(目的是为了获取获取 AppID 和 APPSecret), 个人无法注册测试账号, 所以无法测试, 这里只是记录接口文档, 由于步骤与上面大体一致, 有需要的时候改一下就好.
接下来用 APPID 和 APPSecret 获取用户信息的步骤基本上与上面公众号一样.
微信开放平台网站: https://open.weixin.qq.com/
步骤也是如下:
第一步: 请求 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 进行校验 |
用户允许授权后, 将会重定向到 redirect_uri 的网址上, 并且带上 code 和 state 参数(同上面公众号一样)
redirect_uri?code=CODE&state=STATE
若用户禁止授权, 则重定向后不会带上 code 参数, 仅会带上 state 参数
redirect_uri?state=STATE
第二步: 通过 code 获取 access_token
接口地址: https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
参数说明:
参数 | 是否必须 | 说明 |
---|---|---|
appid | 是 | 应用唯一标识,在微信开放平台提交应用审核通过后获得 |
secret | 是 | 应用密钥 AppSecret,在微信开放平台提交应用审核通过后获得 |
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 调用接口(可以跳过, 说明步骤)
获取 access_token 后, 进行接口调用, 有以下前提:
1. access_token 有效且未超时;
2. 微信用户已授权给第三方应用帐号相应接口作用域(scope).
对于接口作用域(scope), 能调用的接口有以下:
授权作用域(scope) | 接口 | 接口说明 |
---|---|---|
snsapi_base | /sns/oauth2/access_token | 通过 code 换取 access_token、refresh_token 和已授权 scope |
snsapi_base | /sns/oauth2/refresh_token | 刷新或续期 access_token 使用 |
snsapi_base | /sns/auth | 检查 access_token 有效性 |
snsapi_userinfo | /sns/userinfo | 获取用户个人信息 |
第四步: 获取用户个人信息(UnionID 机制)
此接口用于获取用户个人信息. 开发者可通过 OpenID 来获取用户基本信息. 特别需要注意的是, 如果开发者拥有多个移动应用, 网站应用和公众帐号, 可通过获取用户基本信息中的 unionid 来区分用户的唯一性, 因为只要是同一个微信开放平台帐号下的移动应用, 网站应用和公众帐号, 用户的 unionid 是唯一的. 换句话说, 同一用户, 对同一个微信开放平台下的不同应用, unionid 是相同的. 请注意, 在用户修改微信头像后, 旧的微信头像 URL 将会失效, 因此开发者应该自己在获取用户信息后, 将头像图片保存下来, 避免微信头像 URL 失效后的异常情况.
接口地址:
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
参数说明:
参数 | 是否必须 | 说明 |
---|---|---|
access_token | 是 | 调用凭证 |
openid | 是 | 普通用户的标识,对当前开发者帐号唯一 |
lang | 否 | 国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语,默认为 zh-CN |
正确的返回:
- {
- "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 信息, 以便以后在不同应用中进行用户信息互通.
unionID 是用户统一标识. 统一微信开放平台下面统一用户的 unionID 唯一, 而且公众号如果绑定微信开放平台之后, 公众号接口获取的信息也会加上 unionID.
调用频率限制
接口名 | 频率限制 |
---|---|
通过 code 换取 access_token | 1 万 / 分钟 |
刷新 access_token | 5 万 / 分钟 |
获取用户基本信息 | 5 万 / 分钟 |
来源: http://www.bubuko.com/infodetail-3274462.html