解释微信作为第三方授权登录

版权声明:版权有就有吧。 https://blog.csdn.net/m0_38044453/article/details/85249621

微信开放平台的官网https://open.weixin.qq.com/

这里是文档,

这个图看着来,

1. 用户点击微信登录,这时请求我们自己的应用(一个借口,该接口给页面返回一个微信端的登录地址)。

例如:https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

其中的appid是在开放平台注册应用后获取的secret也是,redirect_uri 是告诉微信,用后授权后,微信需要对我们进行回调的接口(把临时授权code,返回这个接口)这个地址也要与注册的一致。state:我看视屏的时候,这个传你登录的页面,也就是登录成功后想到到的页面(官方解释:用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验)

2. 根据第一步获取的登录地址,页面请求加载微信的登录页面,然后进行确认。

3. 确认后微信会对我们自己的应用进行一个回调,并且给我们一个临时的授权code。

4.根据code+appid+appsecret 请求微信能获取用户信息的access_token。

5.微信返回access_token,我们进行解析,处理保存等。

感觉写的有点水,权当记录了,轻点喷……

package com.lpw.dbvideo.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

/**
 * 微信配置类
 */
@Configuration
@PropertySource(value = "classpath:application.properties")
public class WeChatConfig {
    /**
     * 微信公众号AppId
     */
    @Value("${wx.oa.appid}")
    private String wxOAAppId;
    /**
     * 微信公众号AppSecret
     */
    @Value("${wx.oa.appsecret}")
    private String wxOAAppSecret;

    /**
     * 微信开放平台 openappid
     */
    @Value("${wx.open.appid}")
    private String wxOpenAppId;

    /**
     * 微信开放平台 openappsecret
     */
    @Value("${wx.open.appsecret}")
    private String wxOpenSecret;

    /**
     * 微信开放平台重定向地址
     */
    @Value("${wx.open.redirecturl}")
    private String wxOpenRedirectUrl;

    /**
     * 微信开放平台二维码地址
     */
//    private static final String OPEN_QRCODE_URL = "https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect";
    private static final String OPEN_QRCODE_URL = "127.0.0.1:8081/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=SCOPE&state=%s#wechat_redirect";

    /**
     * 开放平台获取access_token 地址
     */
    private static final String OPEN_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";

    /**
     * 获取微信用户信息的接口
     */
    private static final String OPEN_USER_INFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s";

    public String getWxOAAppId() {
        return wxOAAppId;
    }

    public void setWxOAAppId(String wxOAAppId) {
        this.wxOAAppId = wxOAAppId;
    }

    public String getWxOAAppSecret() {
        return wxOAAppSecret;
    }

    public void setWxOAAppSecret(String wxOAAppSecret) {
        this.wxOAAppSecret = wxOAAppSecret;
    }

    public String getWxOpenAppId() {
        return wxOpenAppId;
    }

    public void setWxOpenAppId(String wxOpenAppId) {
        this.wxOpenAppId = wxOpenAppId;
    }

    public String getWxOpenSecret() {
        return wxOpenSecret;
    }

    public void setWxOpenSecret(String wxOpenSecret) {
        this.wxOpenSecret = wxOpenSecret;
    }

    public String getWxOpenRedirectUrl() {
        return wxOpenRedirectUrl;
    }

    public void setWxOpenRedirectUrl(String wxOpenRedirectUrl) {
        this.wxOpenRedirectUrl = wxOpenRedirectUrl;
    }

    public static String getOpenQrcodeUrl() {
        return OPEN_QRCODE_URL;
    }

    public static String getOpenAccessTokenUrl() {
        return OPEN_ACCESS_TOKEN_URL;
    }

    public static String getOpenUserInfoUrl() {
        return OPEN_USER_INFO_URL;
    }
}
package com.lpw.dbvideo.login.controller;

import com.lpw.dbvideo.config.WeChatConfig;
import com.lpw.dbvideo.user.service.UserService;
import com.lpw.dbvideo.utils.JsonData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;

/**
 * 第一步 用户前端请求进入(本项目中的)接口,接口请求微信平台,微信平台给(本项目中的)接口返回一个授权地址,(本项目中的)接口再给前端返回,前端展示;
 * 第二步 用户前端进行确认(即扫码确认),接着微信平台会重定向到(本项目中的)接口,并且带上一个授权临时票据code;
 * 第三步 根据code加上appid和appsecret 请求微信获取token,微信返回token结束。
 */
@Controller
@RequestMapping("/api/wechat")
public class WeChatController {

    @Autowired
    private WeChatConfig weChatConfig;

    @Autowired
    private UserService userService;

    /**
     * 微信扫一扫登录,获取微信二维码的地址
     * @param state  用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验
     * @return
     * @throws UnsupportedEncodingException
     */
    @RequestMapping("login")
    @ResponseBody
    @CrossOrigin
    public JsonData loginUrl(@RequestParam(value = "state")String state) throws UnsupportedEncodingException {

        String redirecrUrl = weChatConfig.getWxOpenRedirectUrl(); // 获取开放平台重定向地址
        String callBackUrl = URLEncoder.encode(redirecrUrl,"UTF-8"); // 进行编码
        String qrcodeUrl = String.format(WeChatConfig.getOpenQrcodeUrl(),weChatConfig.getWxOpenAppId(),callBackUrl,state);
        return JsonData.success(qrcodeUrl);
    }

    /**
     *  微信客户端的回调接口
     * @param code 用户确认后,微信端重定向会这个接口,带上授权临时票据(code)
     * @param state 上面我们给微信端传的state,微信端会继续返回给我们
     * @param response HttpServletResponse
     */
    @GetMapping("/user/callback")
    public void wechatUserCallBack(String code, String state, HttpServletResponse response){
        userService.saveWeChatUser(code);
    }

}
package com.lpw.dbvideo.utils;

import com.google.gson.Gson;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.util.HashMap;
import java.util.Map;

/**
 * 封装http get,post
 */
public class HttpUtils {

    public static final Gson gson = new Gson();

    /**
     * get方法
     * @param url
     * @return
     */
    public static Map<String, Object> doGet(String url){

        Map<String, Object> map = new HashMap<String, Object>();
        CloseableHttpClient httpClient = HttpClients.createDefault();

        RequestConfig requestConfig =RequestConfig.custom().setConnectTimeout(5000) // 连接超时
                .setConnectionRequestTimeout(5000) // 请求超时
                .setSocketTimeout(5000) // 连接socket超时
                .setRedirectsEnabled(true) // 允许重定向
                .build();

        HttpGet httpGet = new HttpGet(url);
        httpGet.setConfig(requestConfig);
        try{
            HttpResponse httpResponse = httpClient.execute(httpGet);
            if(httpResponse.getStatusLine().getStatusCode() == 200){
                String jsonResult = EntityUtils.toString(httpResponse.getEntity());
                map = gson.fromJson(jsonResult, map.getClass());
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try{
                httpClient.close();
            }catch (Exception e){
                e.printStackTrace();            }
        }
        return map;
    }

    /**
     * 封装 post
     * @param url 请求路径
     * @param data 请求数据
     * @param timeout 过期时间
     * @return
     */
    public static  String doPost(String url, String data,int timeout ){

        CloseableHttpClient httpClient = HttpClients.createDefault();
        // 设置超时
        RequestConfig requestConfig =RequestConfig.custom().setConnectTimeout(timeout) // 连接超时
                .setConnectionRequestTimeout(timeout) // 请求超时
                .setSocketTimeout(timeout) // 连接socket超时
                .setRedirectsEnabled(true) // 允许重定向
                .build();

        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestConfig);
        httpPost.addHeader("Content-type", "text/html;charset=UTF-8");
        if(data != null && data instanceof String){
            StringEntity stringEntity = new StringEntity(data, "UTF-8");
            httpPost.setEntity(stringEntity);
        }
        try{
            CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
            HttpEntity httpEntity = httpResponse.getEntity();
            if(httpResponse.getStatusLine().getStatusCode() == 200){
                String jsonResult = EntityUtils.toString(httpEntity);
                return jsonResult;
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try{
                httpClient.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        return null;
    }
}
<!-- httpclient 相关-->
		<dependency>
			<groupId>org.apache.httpcomponents</groupId>
			<artifactId>httpclient</artifactId>
			<version>4.5.3</version>
		</dependency>
		<dependency>
			<groupId>org.apache.httpcomponents</groupId>
			<artifactId>httpmime</artifactId>
			<version>4.5.2</version>
		</dependency>
		<dependency>
			<groupId>commons-codec</groupId>
			<artifactId>commons-codec</artifactId>
		</dependency>
		<dependency>
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
			<version>1.1.1</version>
		</dependency>
		<dependency>
			<groupId>org.apache.httpcomponents</groupId>
			<artifactId>httpcore</artifactId>
		</dependency>

由于测试的时候没有开放平台的认证账号,所以只好自己写一个服务模拟测试(有出入谅解,毕竟不知道微信怎么做的)。附上码云地址

猜你喜欢

转载自blog.csdn.net/m0_38044453/article/details/85249621