天天看点

java微信二维码第三方后台登陆实现 ( 二 )

二.后台实现微信登录

1.生成二维码

a.利用user微服务实现生成二维码功能

b.需要把user微服务端口号改为8150(看需求决定)

c.前端登录页面端口号地址也改为8150

d.把RestController变为Controller(因为前端展示的是二维码图片,不然就会生成json数据展示在页面)

2.用户扫描二维码 微信给客户端发送一个code

3.通过appid+appsecret+code获取access_token+openid

4.通过access_token+openid获取用户个人信息

5.把用户个人信息保存到数据库

6.返回一个token信息给前端

package com.atguigu.controller;

import com.atguigu.entity.MemberCenter;
import com.atguigu.service.MemberCenterService;
import com.atguigu.utils.HttpClientUtils;
import com.atguigu.utils.JwtUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.gson.Gson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;

//不能转化为json数据
@Controller
//前端需要跳转的页面
@RequestMapping("/api/ucenter/wx")
@CrossOrigin
public class WxApiController {
    //拿到配置文件里的数据
    @Value("${wx.open.app_id}")
    private String WX_OPEN_APP_ID;
    @Value("${wx.open.app_secret}")
    private String WX_OPEN_APP_SECRET;
    @Value("${wx.open.redirect_url}")
    private String WX_OPEN_REDIRECT_URL;

    @Autowired
    private MemberCenterService memberCenterService;

    //获取二维码
    @GetMapping("/login")
    public String qrCode() throws UnsupportedEncodingException {
        //%s表示占位符,需要我们设定值,其他则是固定式
        String baseUrl = "https://open.weixin.qq.com/connect/qrconnect" +
                "?appid=%s" +
                "&redirect_uri=%s" +
                "&response_type=code" +
                "&scope=snsapi_login" +
                "&state=%s" +
                "#wechat_redirect";
        //转化路径中的\\,符合微信二维码路径标准
        String redirectUrl = URLEncoder.encode(WX_OPEN_REDIRECT_URL, "UTF-8");
        //自己设置的
        String state = "zhuyonghaoshuai";
        //给上面路径中的%s占位符赋值
        String retUrl = String.format(baseUrl, WX_OPEN_APP_ID, redirectUrl, state);
        //将结果返回,就可以生成二维码
        return "redirect:" + retUrl;
    }

    @GetMapping("/callback")
    //编写callback回调方法
    //扫描二维码后微信会返回一个code
    public String callback(String code) throws Exception {
        //向认证服务器发送请求换取access_token和open_id
        String baseAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token" +
                "?appid=%s" +
                "&secret=%s" +
                "&code=%s" +
                "&grant_type=authorization_code";
        //给上面路径中的%s占位符赋值
        String baseAccessTo = String.format(baseAccessTokenUrl, WX_OPEN_APP_ID, WX_OPEN_APP_SECRET, code);
        //模拟http请求
        String retUrl = HttpClientUtils.get(baseAccessTo);
        //将http请求转换为map,利用map的key-value取值。因为只需要拿到其中的access_token和open_id两个值,其他值看需求拿取
        Gson gson = new Gson();
        HashMap retMap = gson.fromJson(retUrl, HashMap.class);
        //转化为map后去除需要的属性
        String access_token = (String) retMap.get("access_token");
        String openid = (String) retMap.get("openid");
        //根据access_token和openid获取用户信息
        String userInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
                "?access_token=%s" +
                "&openid=%s";
        String userInfo = String.format(userInfoUrl, access_token, openid);
        //模拟http请求
        String userInfos = HttpClientUtils.get(userInfo);
        //将http请求转换为map,利用map的key-value取值。
        //注意这里是用户想要返回给我们的信息
        HashMap userInfoMap = gson.fromJson(userInfos, HashMap.class);
        //一般需要返回头像和昵称,openid是必须要返回的,其他看需求
        String nickname = (String) userInfoMap.get("nickname");
        String headimgurl = (String) userInfoMap.get("headimgurl");
        QueryWrapper<MemberCenter> wrapper = new QueryWrapper<>();
        wrapper.eq("openid", openid);
        //通过openid查询数据库是否有用户数据
        MemberCenter memberCenter = memberCenterService.getOne(wrapper);
        //如果没有就将用户返回的数据存储到数据库
        if (memberCenter == null) {
            //拿到用户信息后,需要保存到数据库
            memberCenter = new MemberCenter();
            //头像地址,昵称 和 openid
            memberCenter.setAvatar(headimgurl);
            memberCenter.setNickname(nickname);
            memberCenter.setOpenid(openid);
            memberCenterService.save(memberCenter);
        }
        //最后将加密的token返回给前端首页,具体返回到哪个页面看需求
        String token = JwtUtils.geneJsonWebToken(memberCenter);
        return "redirect:http://127.0.0.1:3000?token="+token;
    }
}

           

2.登陆后用户信息展示

//通过token获取用户信息
    @GetMapping("queryUserInfoByToken/{token}")
    public RetVal queryUserInfoByToken(@PathVariable("token") String token) {
        //利用JWT另外一个方法获取用户信息
        Claims claims = JwtUtils.checkJWT(token);
        String id = (String) claims.get("id");
        String nickname = (String) claims.get("nickname");
        String avatar = (String) claims.get("avatar");
       // 创建一个MemberCenterVo,封装需要的数据返回,保证数据的安全性
        MemberCenterVo memberCenterVo = new MemberCenterVo();
        memberCenterVo.setId(id);
        memberCenterVo.setAvatar(avatar);
        memberCenterVo.setNickname(nickname);
        return RetVal.success().data("memberCenterVo",memberCenterVo);
    }
}