授权流程技术说明
官网授权流程图如下:
步骤1:第三方平台方获取预授权码(pre_auth_code)
该API用于获取预授权码。预授权码用于公众号或小程序授权时的第三方平台方安全验证。
接口调用请求说明
http请求方式: POST(请使用https协议)
https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?component_access_token=xxx
POST数据示例:
{
"component_appid":"appid_value"
}
请求参数说明
参数 | 说明 |
component_appid | 第三方平台方appid |
返回结果示例
{"pre_auth_code":"Cx_Dk6qiBE0Dmx4EmlT3oRfArPvwSQ-oa3NL_fwHM7VI08r52wazoZX2Rhpz1dEw","expires_in":600}
结果参数说明
参数 | 说明 |
pre_auth_code | 预授权码 |
expires_in | 有效期,为10分钟 |
步骤2:引入用户进入授权页
第三方平台方可以在自己的网站中放置“微信公众号授权”或者“小程序授权”的入口,或生成授权链接放置在移动网页中,引导公众号和小程序管理员进入授权页。
我们这里才用网页扫码授权的方式,注意这个授权地址必须放在我们自己的网页里打开,我们在申请填的域名下打开才行
就是上面这个,下面我们会写一个简单的授权页面,动态将获取到的参数放入授权跳转地址中.
方式一:授权注册页面扫码授权
授权页网址为:
https://mp.weixin.qq.com/cgi-bin/componentloginpage?component\_appid=xxxx&pre\_auth\_code=xxxxx&redirect\_uri=xxxx&auth\_type=xxx。
参数 | 是否必填 | 参数说明 |
component_appid | 是 | 第三方平台方appid |
pre_auth_code | 是 | 预授权码 |
redirect_uri | 是 | 回调URI |
auth_type | 否 | 要授权的帐号类型, 1则商户扫码后,手机端仅展示公众号、2表示仅展示小程序,3表示公众号和小程序都展示。如果为未制定,则默认小程序和公众号都展示。第三方平台开发者可以使用本字段来控制授权的帐号类型。 |
biz_appid | 否 | 指定授权唯一的小程序或公众号 |
获取预授权码以及返回一个授权页面代码:
@RestController
public class PreAuthController {
@Resource
private WeiXinApi weiXinApi;
@GetMapping("/testpreauthapi")
public ModelAndView testPreAuthApi() {
Map<String, Object> params = new HashMap<>();
params.put("component_appid", OpenComponentParams.appId);// 前面已经获取到的平台appid
// 获取预授权码 preAuthCode
Map<String, Object> preauthcode =
weiXinApi.preauthcode(OpenComponentParams.ACCESS_TOKEN, params);// 前面已经获取的平台token
// 授权地址需要的参数信息
Map<String, Object> result = new HashMap<>();
result.put("component_appid", OpenComponentParams.appId);
result.put("pre_auth_code", preauthcode.get("pre_auth_code"));// 预授权码
result.put("redirect_uri", "https://testwxopenauth.linshang.com/callback");// 回调url
result.put("auth_type", "2");
return new ModelAndView("auth", result);// 返回我们自己写的授权页面
}
}
简单实现的页面代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- 我们需要跳转的地址 -->
<a
th:href="@{https://mp.weixin.qq.com/cgi-bin/componentloginpage(component_appid=${component_appid},pre_auth_code=${pre_auth_code},redirect_uri=${redirect_uri},auth_type=2)}">发起授权</a>
</body>
</html>
封装的微信api
@FeignClient(name = "weixinapi", url = "https://api.weixin.qq.com")
public interface WeiXinApi {
/**
* 获取第三方平台component_access_token.
*
* @param params 发送的参数
* @return 请求结果
*/
@PostMapping("/cgi-bin/component/api_component_token")
Map<String, Object> componentToken(Map<String, Object> params);
/**
* 获取预授权码pre_auth_code.
*
* @param componentAccessToken 请求token
* @param params 第三方平台方appid
* @return 预授权码pre_auth_code
*/
@PostMapping(value = "/cgi-bin/component/api_create_preauthcode")
Map<String, Object> preauthcode(
@RequestParam("component_access_token") String componentAccessToken,
Map<String, Object> params);
/**
* 使用授权码换取公众号或小程序的接口调用凭据和授权信息.
*
* @param componentAccessToken 平台可访问授权码
* @param params post的参数
* @return api执行结果
*/
@PostMapping("/cgi-bin/component/api_query_auth")
Map<String, Object> apiQueryAuth(
@RequestParam("component_access_token") String componentAccessToken,
Map<String, Object> params);
}
静态类:
public class OpenComponentParams {
public static String aesKey = "0JpPmBUBCe7EFeEg9EDcEklWYGXFNLg6nGMqKV2gDyT"; //aeskey
public static String COMPONENT_TOKEN = "linshang-open-mini"; //平台设定的token
public static String appId = "wx59bfe3a873b9d9f4";//平台appid
public static String secret = "1de8bc72c6c21e8ad3f32218195399b6";//平台秘钥
public static String pre_auth_code="";//预授权码
public static String TICKET = "";// 第三方ticket
public static String ACCESS_TOKEN = "";// 平台token
}
步骤3:使用授权码换取公众号或小程序的接口调用凭据和授权信息
在上一步点击完成扫码授权之后,我们在授权时留的回调地址会接收到微信发来的一个临时auth_code,有效时间比较短,所以在收到回调时,我们马上就用它去获换取authorizer_access_token和authorizer_refresh_token。
接口调用请求说明
http请求方式: POST(请使用https协议)
https://api.weixin.qq.com/cgi-bin/component/api_query_auth?component_access_token=xxxx
POST数据示例:
{
"component_appid":"appid_value" ,
"authorization_code": "auth_code_value"
}
请求参数说明
参数 | 说明 |
component_appid | 第三方平台appid |
authorization_code | 授权code,会在授权成功时返回给第三方平台,详见第三方平台授权流程说明 |
返回结果示例
{
"authorization_info": {
"authorizer_appid": "wxf8b4f85f3a794e77",
"authorizer_access_token": "QXjUqNqfYVH0yBE1iI_7vuN_9gQbpjfK7hYwJ3P7xOa88a89-Aga5x1NMYJyB8G2yKt1KCl0nPC3W9GJzw0Zzq_dBxc8pxIGUNi_bFes0qM",
"expires_in": 7200,
"authorizer_refresh_token": "dTo-YCXPL4llX-u1W1pPpnp8Hgm4wpJtlR6iV0doKdY",
"func_info": [
{
"funcscope_category": {
"id": 1
}
},
{
"funcscope_category": {
"id": 2
}
},
{
"funcscope_category": {
"id": 3
}
}
]
}}
结果参数说明
参数 | 说明 |
authorization_info | 授权信息 |
authorizer_appid | 授权方appid |
authorizer_access_token | 授权方接口调用凭据(在授权的公众号或小程序具备API权限时,才有此返回值),也简称为令牌 |
expires_in | 有效期(在授权的公众号或小程序具备API权限时,才有此返回值) |
authorizer_refresh_token | 接口调用凭据刷新令牌(在授权的公众号具备API权限时,才有此返回值),刷新令牌主要用于第三方平台获取和刷新已授权用户的access_token,只会在授权时刻提供,请妥善保存。 一旦丢失,只能让用户重新授权,才能再次拿到新的刷新令牌 |
func_info | 授权给开发者的权限集列表,ID为1到26分别代表: 1、消息管理权限 2、用户管理权限 3、帐号服务权限 4、网页服务权限 5、微信小店权限 6、微信多客服权限 7、群发与通知权限 8、微信卡券权限 9、微信扫一扫权限 10、微信连WIFI权限 11、素材管理权限 12、微信摇周边权限 13、微信门店权限 15、自定义菜单权限 16、获取认证状态及信息 17、帐号管理权限(小程序) 18、开发管理与数据分析权限(小程序) 19、客服消息管理权限(小程序) 20、微信登录权限(小程序) 21、数据分析权限(小程序) 22、城市服务接口权限 23、广告管理权限 24、开放平台帐号管理权限 25、 开放平台帐号管理权限(小程序) 26、微信电子发票权限 41、搜索widget的权限 请注意: 1)该字段的返回不会考虑公众号是否具备该权限集的权限(因为可能部分具备),请根据公众号的帐号类型和认证情况,来判断公众号的接口权限。 |
代码:
@RestController
public class CallbackController {
private Log log = LogFactory.getLog(this.getClass());
@Resource
private WeiXinApi weiXinApi;
@RequestMapping("/callback")
public String callback() {
Map<String, String[]> parameterMap = WebUtils.getRequest().getParameterMap();
if (parameterMap.containsKey("auth_code") && parameterMap.containsKey("expires_in")) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("authorization_code", StringUtils.join(parameterMap.get("auth_code"), ","));
params.put("component_appid", OpenComponentParams.appId);
//获取小程序的凭据和授权信息
Map<String, Object> result =
weiXinApi.apiQueryAuth(OpenComponentParams.ACCESS_TOKEN, params);
//保存调用凭据和授权信息
log.info(result);
}
return "info";
}
}
这里拿到了authorizer_access_token之后就可以代小程序进行业务接口的调用开发了,注意这个token有效时间为两个小时,所以要及时刷新,authorizer_refresh_token也要保存好。
最后:用户授权时是通过我们授权地址填的回调通知我们的,有时候用户会取消和更新授权,取消和更新的授权通知和发送ticket那个接口是一样的,所以我们在开始拿ticket的接口要做好消息事件的类型接收,针对不同的通知做不同的处理。
当公众号对第三方平台进行授权、取消授权、更新授权后,微信服务器会向第三方平台方的授权事件接收URL(创建第三方平台时填写)推送相关通知。
POST数据示例(授权成功通知)
<xml>
<AppId>第三方平台appid</AppId>
<CreateTime>1413192760</CreateTime>
<InfoType>authorized</InfoType>
<AuthorizerAppid>公众号appid</AuthorizerAppid>
<AuthorizationCode>授权码(code)</AuthorizationCode>
<AuthorizationCodeExpiredTime>过期时间</AuthorizationCodeExpiredTime>
<PreAuthCode>预授权码</PreAuthCode>
<xml>
POST数据示例(取消授权通知)
<xml>
<AppId>第三方平台appid</AppId>
<CreateTime>1413192760</CreateTime>
<InfoType>unauthorized</InfoType>
<AuthorizerAppid>公众号appid</AuthorizerAppid>
</xml>
POST数据示例(授权更新通知)
<xml>
<AppId>第三方平台appid</AppId>
<CreateTime>1413192760</CreateTime>
<InfoType>updateauthorized</InfoType>
<AuthorizerAppid>公众号appid</AuthorizerAppid>
<AuthorizationCode>授权码(code)</AuthorizationCode>
<AuthorizationCodeExpiredTime>过期时间</AuthorizationCodeExpiredTime>
<PreAuthCode>预授权码</PreAuthCode>
<xml>
字段说明:
字段名称 | 字段描述 |
AppId | 第三方平台appid |
CreateTime | 时间戳 |
InfoType | unauthorized是取消授权,updateauthorized是更新授权,authorized是授权成功通知 |
AuthorizerAppid | 公众号或小程序 |
AuthorizationCode | 授权码,可用于换取公众号的接口调用凭据,详细见上面的说明 |
AuthorizationCodeExpiredTime | 授权码过期时间 |
PreAuthCode | 预授权码 |