SpringBoot:微信授权扫一扫登陆整体流程超详细

在开始讲解微信登陆前先补一些知识点

Step1:常见互联网登陆方式

1.手机号或邮箱注册

优点

​ 1)企业获取了用户的基本资料信息,利于后续业务发展推送营销类信息

​ 2)用户可以用个手机号或者邮箱获取对应的app福利 注册送优惠券

​ 3)反馈信息的时候方便,直接报手机号即可账户出问题,被盗等

缺点:

​ 1)步骤多

​ 2)如果站点不安全,如站点被攻击,泄露个人信息,如手机号、密码等

​ 3)少量不良企业贩卖用户信息,如手机号等

2.OAuth2.0一键授权登陆

例子:豆瓣:www.douban.com

优点:使用便捷,用户体验好,数据相对安全

缺点:

​ 1)反馈问题麻烦,比较难知道唯一标识 openid

​ 22)如果是企业下面有多个应用,其中有应用不支持Auth2.0登陆,则没法左到用户信息打通,不能复用等,如app接入了微信授权登陆,但是网站没有,则打不通,或者授权方只提供了一种终端授权,则信息无法打通。

3.选择方式

1)看企业和实际业务情况

2)务必区分,普通密码和核心密码

Step2:微信扫一扫功能开发前准备

微信开放平台

网站:htts://open.weixin.qq.com/

无奈微信开放平台对开发者不友好,一定要公司营业执照 + 300元认证认证,才可以认证微信开放平台接入微信登录。

如果你有自己的应用,还需要备案等,但这里我会把整体的流程讲解

有三个点要注意

appid:就是你的应用唯一id

appsecret:密钥

code:授权码

redirect_url:授权回调域(这里重点说一下,你应用那里写的是多少,你的配置中一定要一样,)

比如你在当前www.baidu.com 微信登陆,微信那边会回调你配置的地址,它会把一些code重要参数给你,如果你地址不对,那么你就接收不到参数,自然后面的操作也是无法完成的。感觉有些懵继续往下看就明白了
在这里插入图片描述

封装一个Http请求类,用于我们扫一扫后向微信平台发请求获取信息用的

Step1:添加依赖

		<!--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>
		<!--gson工具,封装http的时候使用 做map类型的转换-->
		<dependency>
			<groupId>com.google.code.gson</groupId>
			<artifactId>gson</artifactId>
			<version>2.8.0</version>
		</dependency>

Step2:封装GET\POST请求

/**
 * 封装http get post方法
 */
public class HttpUtils {

    private static final Gson gson = new Gson();

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

        Map<String,Object> map = new HashMap<>();

        CloseableHttpClient httpClient = HttpClients.createDefault();


        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(5000)//连接超时
                .setConnectionRequestTimeout(5000)//请求连接超时
                .setSocketTimeout(5000)
                .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());
                //转换key value形式
                map = gson.fromJson(jsonResult,map.getClass());
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //关闭请求
            try {
                httpClient.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }

        return map;
    }


    public static String doPost(String url,String data,int timeout){

        CloseableHttpClient httpClient = HttpClients.createDefault();

        //超时设置
        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(timeout)//连接超时
                .setConnectionRequestTimeout(timeout)//请求连接超时
                .setSocketTimeout(timeout)
                .setRedirectsEnabled(true)//允许重定向
                .build();
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestConfig);
        //增加头信息
        httpPost.addHeader("Content-Type","text/html;chartset=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 result  = EntityUtils.toString(httpEntity);
                return result;
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                httpClient.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        return null;
    }
}

Step3:微信登陆回调本地域名映射工具NATAPP

以上步骤完成后,我们还需要一个ip映射工具

什么是域名映射: 就是当前开发机器的ip 通过和域名绑定,让外部网络可以通过域名就行访问到本地机器接口

原来是使用Ngrock,但现在不能用了,这里我们使用新的工具NATAPP

官网:https://natapp.cn/

文档:https://natapp.cn/article/natapp_newbie

因为文档有很详细的讲解,这里就不再演示,有一点,配置authtoken的文件,需要放在natapp.exe同级目录下,才能映射出来地址,成功后是这个样子的。我这里使用的是免费的,每次启动会给一个随机的,如果你有线上应用,那么你可以买一个自定义域名映射,也不贵,好像10块钱一个月
在这里插入图片描述

置好后我们就可以用它给的地址,去访问我们的服务了

在这里插入图片描述

是不是很好用,这样我们就不用去购买域名去配置服务器了,但是一定不要去做一些非法的事情

这个东西有时也会断电,因为它也是建立一个服务器么,不稳定,但在你开发测试频率不高,也不影响

Step4:微信OAuth2.0交互流程讲解

一定要明白这个流程,不然你还是懵懵的

三个角色:

1)微信用户也就是你!

2)第三方应用也就是你访问的网站

3)微信开放平台

流程

1.微信用户请求第三方应用登陆

2.网站请求微信开放平台OAuth2.0授权登陆

3.微信开放平台收到请求后返回二维码扫一扫

4.微信用户确定信息返回给微信开放平台

5.微信开放平台收到用户确认后,会带上一个票据,调取网站后台 后台得到一个参数code

6.通过code,去微信开放平台发送请求,通过code加上appid和appsecret换取token令牌,token里包含用户信息

7.微信开放平台返回access_token,去拿去用户信息
在这里插入图片描述

Step5:微信授权一键登陆之授权URL获取

第一步!:请求CODE

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

上面是官网的实例,而我们请求生成二位码时需要重新拼接里面的值来生成我们的二位码

Step1:添加微信配置

XXX都是你自己微信开放平台的值

appid和appsecret都是已经申请过的应用,需要有公司注册,还要交300块钱,url就是一个扫码后的回调地址,这个是你应用的回调域名地址,你那里写多少,这里就要写多少才能回调成功,回调后的操作就是你之后拿code再像微信开放平台获取用户信息的一些操作

#微信开放平台配置
wxopen.appid=XXXX
wxopen.appsecret=XXX
#授权回调url接口
wxopen.redirect_url=http://XXX你自己的域名/api/v2/wechat//user/callback

Step2:微信配置类

里面的参数在后面都会一一用到,记得添加get、set方法,这里我就不写了

/**
 * 微信配置类
 */
@Configuration
@PropertySource(value = "classpath:application.properties")
public class WeChatConfig {

    /**
     * 开放平台appid
     */
    @Value("${wxopen.appid}")//bean对象属性注入
    private String openAppId;

    /**
     * 开放平台密钥
     */
    @Value("${wxopen.appsecret}")
    private String openAppsecret;

    /**
     * 开放平台回调地址
     */
    @Value("${wxopen.redirect_url}")
    private String openRedirectUrl;

    /**
     * 微信平台的二位码链接
     */
    private final static String OPEN_QRCODE_URL= "https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_login&state=%s#wechat_redirect";

    /**
     * 开放平台获取access_token地址
     */
    private final static 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 final static String OPEN__USER_INFO_URL="https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%slang=zh_CN";
}

Step3:控制层

@Controller
@RequestMapping("api/v2/wechat")
public class WechatController {

    @Autowired
    private WeChatConfig weChatConfig;

    @Autowired
    private UserService userService;
    /**
     * 拼装扫一扫登陆url
     * @return
     * @accessPage:扫码登陆回调后回到的页面
     */
    @GetMapping("login_url")
    @ResponseBody
    public Dto loginUrl(@RequestParam(value = "access_page",required = true)String accessPage) throws UnsupportedEncodingException {

        //获取开放平台重定向地址
        String rediectUrl =weChatConfig.getOpenRedirectUrl();

        //处理链接编码
        String callbackUrl = URLEncoder.encode(rediectUrl,"GBK");

        //拼装扫码链接
        String qrcodeUrl = String.format(WeChatConfig.getOpenQrcodeUrl(),
                weChatConfig.getOpenAppId(),callbackUrl,accessPage);
        return DtoUtil.returnDataSuccess(qrcodeUrl);
    }
}

测试

在这里插入图片描述

可以看到我们频接了对应的url,拿到这个url后,我们在打开一个新的页面去访问,就会生成二位码,只要你的appid和和回调地址以及appsecret是真实的,就能出现二位码,如果不存在,会提示你appid参数错误等信息
在这里插入图片描述

注意:这里这步,我们只是先生成了二位码,而并没有做一些回调操作,访问的这个地址是微信开放平台的,这里就需要等待用户扫描,确认后!才会进行地址的回调,我们再做一些其它的操作。这里就是流程上面的第四步

Step6:授权回调获取用户信息

完成上面的操作后,这里先将一下流程,用户扫完码确认登陆后,微信平台就会回调我们配置好的地址,将code发送给我们。拿到code后我们再请求微信平台获取用户token再拿token获取用户信息,所以这个流程大家一定要清除,如果你没有上线应用,没关系,代码整体的流程就这些,明白这个过程就行
在这里插入图片描述

在上面微信的配置类里我们还加了这两个属性,上面忘说了,使用%s的方式,就可以频接字符串

OPEN_ACCESS_TOKEN_URL:根据回调给我们的code,再去访问微信平台获取用户token
OPEN__USER_INFO_URL:拿到用token后再去访问微信平台获取用户信息,比如头像名称等

Step1:Service接口

    User saveWeChatUser(String code);

Step2:Service实现类

用到了我们上面写好的封装方法,过程不复杂,就是发请求拿对应的值再发请求就可以了

    @Override
    public User saveWeChatUser(String code) {

        //获取微信开放平台access_tokenurl地址 频接字符串
        String accessTokenUrl = String.format(WeChatConfig.getOpenAccessTokenUrl(),
                weChatConfig.getOpenAppId(),weChatConfig.getOpenAppsecret(),code);
        //http发送请求 拿对应的accessToken和openid
        Map<String,Object> baseMap = HttpUtils.doGet(accessTokenUrl);
        if(baseMap == null || baseMap.isEmpty()){return null;}
        String accessToken = (String)baseMap.get("access_token");
        String openId = (String)baseMap.get("openid");

        //通过accessToken获取用户信息
        String userInfoUrl = String.format(WeChatConfig.getOpen_userInfoUrl(),accessToken,openId);
        Map<String,Object> baseUserMap = HttpUtils.doGet(userInfoUrl);
        if(baseUserMap == null || baseUserMap.isEmpty()){return null;}
        //获取需要的用户信息 编码问题,不做处理会乱码
        String nickname = (String)baseMap.get("nickname");
        //微信开放平台那边性别是double
        Double sex = (Double)baseMap.get("sex");
        //用于数据的库存储,我这里再给它转成int类型
        int sex = sexTemp.intValue();
        String province = (String)baseMap.get("province");//
        String city = (String)baseMap.get("city");
        String headimgurl = (String)baseMap.get("headimgurl");
        //转码
        try {
            nickname = new String(nickname.getBytes("ISO-8859-1"), "UTF-8");
            finalAddress = new String(finalAddress.getBytes("ISO-8859-1"), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        
        //这里做一些保存用户信息的操作
        return null;
    }

在这里插入图片描述

具体的有一些参数值,需要哪些去官网找
在这里插入图片描述
拿到所有信息后,根据自己需求,保存用户信息,根据openid查询数据库是否已存在微信用户信息等,不存在再保存,至于一些用户在平台上改变一些头像昵称等,那些都是在修改做的操作,一开始保存信息就不再做查询更新了

猜你喜欢

转载自blog.csdn.net/q736317048/article/details/111878445