[Вход в WeChat] Java реализует авторизацию веб-страницы WeChat и авторизацию приложения

WeChat

предисловие

Авторизация веб-страницы входа в WeChat и авторизация приложения
Платеж WeChat JSAPI
Оплата приложения WeChat
Приложение WeChat и возврат JSAPI
Оплата мобильного сайта Alipay
Оплата через приложение Alipay
Alipay возврат
Все вышеперечисленное выкладываю в свой личный паблик аккаунт, ищу:Пиратский корабль Ява, в конце статьи QR-код официального аккаунта! Если вы думаете, что будете использовать его в своем будущем развитии, вы можете обратить внимание!Используйте меньше обходных путей...

официальная документация

H5 Адрес документа для авторизации входа в WeChat

Developers.WeChat.QQ.com/doc/off и ACC…

Авторизация входа в приложение WeChat

Developers.WeChat.QQ.com/doc/О, пилатес…

Руководство по доступу к iOS

Developers.WeChat.QQ.com/doc/О, пилатес…

Руководство по доступу к Android

Developers.WeChat.QQ.com/doc/О, пилатес…

Шаги процесса

Авторизация входа в 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;
    }
}
Спасибо за просмотр, если вам это нравится, вы можете следить за этим! Общедоступная учетная запись для обмена учебными ресурсами по Java, техническими статьями и практическим опытом~

Добро пожаловать на общедоступный номер~