предисловие
Авторизация веб-страницы входа в WeChat и авторизация приложения
Платеж WeChat JSAPI
Оплата приложения WeChat
Приложение WeChat и возврат JSAPI
Оплата мобильного сайта Alipay
Оплата через приложение Alipay
Alipay возврат
Все вышеперечисленное выкладываю в свой личный паблик аккаунт, ищу:Пиратский корабль Ява, в конце статьи QR-код официального аккаунта! Если вы думаете, что будете использовать его в своем будущем развитии, вы можете обратить внимание!Используйте меньше обходных путей...
официальная документация
H5 Адрес документа для авторизации входа в WeChat
Авторизация входа в приложение WeChat
Руководство по доступу к iOS
Руководство по доступу к Android
Шаги процесса
Авторизация входа в H5 WeChat
- Направьте пользователя на страницу авторизации, чтобы согласиться с авторизацией и получить код.
- Код обмена для авторизации веб-страницы access_token (отличается от access_token в базовой поддержке)
- При необходимости разработчик может обновить веб-страницу, чтобы авторизовать access_token, чтобы избежать истечения срока действия.
- Получить основную информацию о пользователе через авторизацию веб-страницы access_token и openid (поддерживает механизм UnionID)
**Вопрос 1: В чем разница между **областью действия, являющейся snsapi_base, и областью действия, являющейся snsapi_userinfo?
snsapi_base автоматически авторизуется и автоматически переходит на страницу обратного вызова, в то время как snsapi_userinfo требует ручного согласия пользователя.
**Вопрос 2:** В чем разница между авторизацией на веб-странице access_token и обычным access_token?
Когда обычный access_token получает информацию о пользователе, если пользователь не следует, полученная информация пуста. Access_token, авторизованный веб-страницей, может быть получен до тех пор, пока пользователь разрешает это, независимо от того, обращает ли пользователь внимание или нет.
**Вопрос 3:**В чем разница между UnionID и openid?
unionid одинаков для разных приложений (мобильное приложение, веб-приложение и официальный аккаунт) на одной и той же открытой платформе WeChat.
OpenID отличается для разных приложений на одной и той же открытой платформе WeChat.Например, если пользователь авторизует приложение A и приложение B, то два openid пользователя будут разными, и одно приложение соответствует одному openid.Для приложения A openid остается без изменений.
**Вопрос 4:** О механизме UnionID
То есть, если разработчик имеет несколько официальных учетных записей или ему необходимо объединить учетные записи пользователей между официальными учетными записями и мобильными приложениями, ему необходимо перейти на открытую платформу WeChat (open.weixin.qq.com), чтобы привязать официальную учетную запись перед использованием Механизм UnionID для удовлетворения вышеуказанных требований.
вытоптанная яма
- Доменное имя redirect_uri не соответствует фоновой конфигурации
Решение. Перейдите в «Настройки официальной учетной записи» — «Настройки функций» — «Авторизация веб-страницы», настройте путь, по которому файл txt хранится во внешнем интерфейсе, например, www.xxx.com/static, а затем нажмите «Отправить». Вы можете проверить, можете ли вы получить доступ к содержимому txt заранее.
- Получить информацию о пользователе WeChat, возвращенный unionID пуст.
Решение: перейдите на открытую платформу WeChat, привяжите официальную учетную запись, и все готово.
Авторизация входа в приложение WeChat
- Третья сторона инициирует запрос на авторизацию WeChat.После того, как пользователь WeChat разрешит авторизацию стороннего приложения, WeChat запустит приложение или перенаправит на сторонний веб-сайт с параметром кода временного билета авторизации;
- Передайте параметр code плюс AppID и AppSecret и т. д. и обменяйте access_token через API;
- Используйте access_token для вызовов интерфейса, чтобы получить основные ресурсы данных пользователей или помочь пользователям реализовать основные операции.
Готов к работе
инструмент проникновения в интранет natapp
Этот инструмент можно использовать для получения доменного имени на этапе разработки.
Получить AppID и AppSecret
Перейдите на открытую платформу WeChat (open.weixin.qq.com), чтобы просмотреть сведения о соответствующем приложении.
Изменить доменное имя обратного вызова авторизации
Перейдите к параметрам конфигурации «Функция официальной учетной записи - Настройки функции» на официальном сайте официальной платформы и настройте доменное имя обратного вызова авторизации веб-страницы в соответствии с инструкциями и спецификациями.
Реализация кода (включая APP и H5)
Параметры конфигурации
application.yml
# 微信相关配置
wx:
#商户 ID
MCH_ID:
# 项目基础域名
BASEURL:
#微信登录-用户同意后回调域名(前端域名)
URL:
# 公众号APP_ID
H_APP_ID:
# 公众号秘钥
H_APP_SECRET:
# app的APP_ID
A_APP_ID:
# APP的 秘钥
A_APP_SECRET:
#微信登录-微信授权基本地址
LOGIN_AUTH_BASE_URL: https://open.weixin.qq.com/connect/oauth2/authorize?
#微信登录-获取ACCESS_TOKEN的URL
LOGIN_ACCESS_TOKEN_URL: https://api.weixin.qq.com/sns/oauth2/access_token?
#微信登录-获取登录人信息的url
LOGIN_USER_INFO_URL: https://api.weixin.qq.com/sns/userinfo?
#微信登录-用户同意后回调地址(前端地址)
LOGIN_RETURN_URL: ${wx.URL}/static/weixinShouQuan.html
#微信登录-应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid), snsapi_userinfo
#(弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息 )
SCOPE: snsapi_userinfo
читать параметры
YmlParament
/**
* 获取yml参数实体
*/
@Component
@Data
public class YmlParament {
/*微信相关字段*/
@Value("${wx.BASEURL}")
private String baseurl;
@Value("${wx.H_APP_ID}")
private String h_app_id;
@Value("${wx.A_APP_ID}")
private String a_app_id;
@Value("${wx.H_APP_SECRET}")
private String h_app_secret;
@Value("${wx.A_APP_SECRET}")
private String a_app_secret;
@Value("${wx.LOGIN_ACCESS_TOKEN_URL}")
private String login_access_token_url;
@Value("${wx.LOGIN_USER_INFO_URL}")
private String login_user_info_url;
@Value("${wx.LOGIN_AUTH_BASE_URL}")
private String login_auth_base_url;
@Value("${wx.LOGIN_RETURN_URL}")
private String login_return_url;
@Value("${wx.SCOPE}")
private String scope;
}
получить код
- H5 получить код
Внешний интерфейс получает URL-адрес авторизации через фон, а затем внешний интерфейс запрашивает URL-адрес для получения кода, а затем запрашивает фон.
WxController
@ApiOperation("获取授权url")
@PostMapping("/getWeiXinLoginUrl")
public R getWeiXinLoginUrl() throws Exception {
String url = ymlParament.getLogin_auth_base_url() + "appid=" + ymlParament.getH_app_id()+ "&redirect_uri=" + ymlParament.getLogin_return_url()
+ "&response_type=code"+ "&scope=snsapi_userinfo" + "&state=STATE#wechat_redirect";
//这里的R是自己自定义的,用于返回结果给前端
return R.ok().data("redirectUrl", url);
}
- ПРИЛОЖЕНИЕ получить код
Приложение использует SDK для запроса авторизации для входа в интерфейсе.После того, как пользователь соглашается на авторизацию, он получает код, а затем запрашивает фон.
Пример кода доступа для авторизации приложения платформы iOS (Пожалуйста, обратитесь к Руководству по доступу к iOS):
-(void)sendAuthRequest
{
//构造SendAuthReq结构体
SendAuthReq* req =[[[SendAuthReq alloc]init]autorelease];
req.scope = @"snsapi_userinfo";
req.state = @"123";
//第三方向微信终端发送一个SendAuthReq消息结构
[WXApi sendReq:req];
}
Пример кода доступа для авторизации приложения платформы Android (Пожалуйста, обратитесь к Руководству по доступу к Android):
{
// send oauth request
Final SendAuth.Req req = new SendAuth.Req();
req.scope = "snsapi_userinfo";
req.state = "wechat_sdk_demo_test";
api.sendReq(req);
}
Код обмена для авторизации на веб-странице access_token, а затем получение информации о пользователе через access_token и openid
WxController
/*H5和app都可以调用*/
@ApiOperation("获取微信用户信息")
@PostMapping(value = "/getWxUserInFo")
public R getWxUserInFo(@RequestBody String body) throws Exception {
String state = JacksonUtil.parseString(body, "state");
String code = JacksonUtil.parseString(body, "code");
//标志哪一个应用,用来获取对应的appid和appsecret
Integer openIdType = JacksonUtil.parseInteger(body, "openIdType");
//1、获取code
if(IsNull.isNull(code) || IsNull.isNull(state)) {
return R.error("参数不能为空");
}
//2、通过code获取accesstoken,UserWxOpenidEums是用来记录应用的,如type1是xxAPP,type2是xx服务号
JSONObject accessToken=WxUtils.getAccessTokenByCode(code,
openIdType==UserWxOpenidEums.TYPE_1.getKey()?ymlParament.getA_app_id():ymlParament.getH_app_id(),
openIdType==UserWxOpenidEums.TYPE_1.getKey()?ymlParament.getA_app_secret():ymlParament.getH_app_secret(),
ymlParament.getLogin_access_token_url());
//3、获取用户信息
JSONObject userinfo=WxUtils.getUserinfo(openIdType==UserWxOpenidEums.TYPE_1.getKey()?ymlParament.getA_app_id():ymlParament.getH_app_id(),
accessToken.getString("openid"), accessToken.getString("access_token"), ymlParament.getLogin_user_info_url());
if(!IsNull.isNull(userinfo.getString("errcode"))){
return R.error(userinfo.getString("errmsg"));
}
return R.ok().data("token", token).data("userinfo",userinfo);
}
WxUtils
/**
* =============>>登录<<=============
* 第二步
* 通过code获取access_token
* 正确时返回的JSON数据包如下:
* {
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE"
}
*/
public static JSONObject getAccessTokenByCode(String code,String appId,String appSecret,String login_access_token_url) throws Exception {
Map<String, String> map = new HashMap<String, String>();
map.put("appid",appId);
map.put("secret",appSecret);
map.put("code",code);
map.put("grant_type","authorization_code");
return (JSONObject)JSON.parse(HttpUtil.get(login_access_token_url, map));
}
/**
* =============>>登录<<=============
* 第三步:刷新access_token(如果需要)
* 正确时返回的JSON数据包如下:
* {
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE"
}
*/
public static JSONObject refreshAccessToken(String appid,String refresh_token) throws Exception {
Map<String, String> map = new HashMap<>();
map.put("appid",appid);
map.put("grant_type","refresh_token");
map.put("refresh_token",refresh_token);
return (JSONObject)JSON.parse(HttpUtil.get("https://api.weixin.qq.com/sns/oauth2/refresh_token?", map));
}
/**
* =============>>登录<<=============
* 第四部,获取用户信息
* 通过code获取access_token
* 正确时返回的JSON数据包如下:
* {
"openid":" OPENID",
"nickname": NICKNAME,
"sex":"1",
"province":"PROVINCE",
"city":"CITY",
"country":"COUNTRY",
"headimgurl": "http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
"privilege":[ "PRIVILEGE1" "PRIVILEGE2" ],
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}
* @throws Exception
*/
public static JSONObject getUserinfo(String appid,String openid,String accessToken,String login_user_info_url) throws Exception {
//先判断下accessToken是否有效
HashMap<String, String> param =new HashMap<String, String>();
param.put("access_token", accessToken);
param.put("openid", openid);
JSONObject check=(JSONObject)JSON.parse(HttpUtil.get("https://api.weixin.qq.com/sns/auth?access_token="+accessToken+"&openid="+openid, param));
//检验授权凭证(access_token)是否有效,如果accessToken失效了,则刷新accessToken
if(!check.getString("errcode").equals("0")) {
accessToken=refreshAccessToken(appid, accessToken).getString("refresh_token");
}
param =new HashMap<String, String>();
param.put("openid",openid);
param.put("access_token",accessToken);
param.put("lang","zh_CN");
return (JSONObject) JSON.parse(HttpUtil.get(login_user_info_url, param));
}
Инструменты
HttpUtil
public static String get(String urlStr, Map<String, String> parameters) throws IOException {
URL url = new URL(urlStr);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setDoInput(true);
httpURLConnection.setDoOutput(true); // 设置该连接是可以输出的
httpURLConnection.setRequestMethod("GET"); // 设置请求方式
httpURLConnection.setRequestProperty("charset", "utf-8");
PrintWriter pw = new PrintWriter(new BufferedOutputStream(httpURLConnection.getOutputStream()));
StringBuffer parameter = new StringBuffer();
parameter.append("1=1");
for (Entry<String, String> entry : parameters.entrySet()) {
parameter.append("&" + entry.getKey() + "=" + entry.getValue());
}
pw.write(parameter.toString());// 向连接中写数据(相当于发送数据给服务器)
pw.flush();
pw.close();
BufferedReader br = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream(), "utf-8"));
String line = null;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) { // 读取数据
sb.append(line + "\n");
}
br.close();
return sb.toString();
}
JacksonUtil
public class JacksonUtil {
public static String parseString(String body, String field) {
ObjectMapper mapper = new ObjectMapper();
JsonNode node;
try {
node = mapper.readTree(body);
JsonNode leaf = node.get(field);
if (leaf != null) {
return leaf.asText();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static Integer parseInteger(String body, String field) {
ObjectMapper mapper = new ObjectMapper();
JsonNode node;
try {
node = mapper.readTree(body);
JsonNode leaf = node.get(field);
if (leaf != null) {
return leaf.asInt();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}