业务复习-微信登录/第三方登录实现

技术点:HttpClient(模拟浏览器的请求),Json转换工具

第一步:密钥ID的配置

wx.open.app_id=wxed9954c01bb89b47

wx.open.app_secret=a7482517235173ddb4083788de60b90e

wx.open.redirect_url=http://localhost:8160/api/ucenter/wx/callback
#wx.open.redirect_url=http://guli.shop/api/ucenter/wx/callback

第二步:整合一个工具类方便读取配置文件属性值,InitializingBean这里很细节,利用初始化将数据加载

package com.guli.ucenter.util;

@Component
//@PropertySource("classpath:application.properties")
public class ConstantPropertiesUtil implements InitializingBean {

	@Value("${wx.open.app_id}")
	private String appId;

	@Value("${wx.open.app_secret}")
	private String appSecret;

	@Value("${wx.open.redirect_url}")
	private String redirectUrl;

	public static String WX_OPEN_APP_ID;
	public static String WX_OPEN_APP_SECRET;
	public static String WX_OPEN_REDIRECT_URL;

	@Override
	public void afterPropertiesSet() throws Exception {
		WX_OPEN_APP_ID = appId;
		WX_OPEN_APP_SECRET = appSecret;
		WX_OPEN_REDIRECT_URL = redirectUrl;
	}
}

第三步:controller层

package com.guli.ucenter.controller.api;

@CrossOrigin
@Controller//注意这里没有配置 @RestController
@RequestMapping("/api/ucenter/wx")
public class WxApiController {

	@GetMapping("login")
	public String genQrConnect(HttpSession session) {

		// 微信开放平台授权baseUrl
		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 = ConstantPropertiesUtil.WX_OPEN_REDIRECT_URL; //获取业务服务器重定向地址
		try {
			redirectUrl = URLEncoder.encode(redirectUrl, "UTF-8"); //url编码
		} catch (UnsupportedEncodingException e) {
			throw new GuliException(20001, e.getMessage());
		}

		// 防止csrf攻击(跨站请求伪造攻击)
		//String state = UUID.randomUUID().toString().replaceAll("-", "");//一般情况下会使用一个随机数
		String state = "imhelen";//为了让大家能够使用我搭建的外网的微信回调跳转服务器,这里填写你在ngrok的前置域名
		System.out.println("state = " + state);

		// 采用redis等进行缓存state 使用sessionId为key 30分钟后过期,可配置
		//键:"wechar-open-state-" + httpServletRequest.getSession().getId()
		//值:satte
		//过期时间:30分钟
		
		//生成qrcodeUrl
		String qrcodeUrl = String.format(
				baseUrl,
				ConstantPropertiesUtil.WX_OPEN_APP_ID,
				redirectUrl,
				state);

		return "redirect:" + qrcodeUrl;
	}
}

第四步:如何生成微信二维码?

请求微信的固定地址,然后向地址后面拼接参数 

 扫描完后,通过请求地址进行回调(需要按照指定规则进行请求),将端口改为8150,创建一个接口callback做回调得到扫码人的信息

 

 第五步:callback回调接口的实现

1.之前第一步扫描二维码callback接口得到的code值——>2.通过code和ID密钥信息去请求微信提供的固定地址得到token访问凭证+openid微信的标识(通过HttpClients访问)——>3.最后拿token和openid再次请求一次微信地址https://api.weixin.qq.com/sns/userinfo

得到用户信息

添加的依赖:

 <!--httpclient-->
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
</dependency>
<!--commons-io-->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
</dependency>
<!--gson-->
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
</dependency>

 通过code,密钥和id得到的用户url是一个String字符串,里面包含token和openid——>我们利用gson将字符串转为map,然后从map中得到指定的数据

第六步:最后将信息提取判断数据库中是否有重复数据,然后插入(先根据openid在数据库中查询,如果已经有了说明之前就扫了一次)

 /**
     * 2.获取扫描人的信息(扫码将人物信息存入数据库),添加数据,返回code类似与手机验证码,随机唯一值->请求微信固定地址
     * 获得access-token:访问凭证
     * openid:每个微信唯一的标识
     * 然后再拿这俩个信息请求获取我们的微信信息->获取扫码人的信息
     */
    @GetMapping("callback")
    public String callback(String code,String state){
        System.out.println("code="+code);

        try {
            //1.拿code值请求wx固定地址,得到access_token和openid
            String baseAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token" +
                    "?appid=%s" +
                    "&secret=%s" +
                    "&code=%s" +
                    "&grant_type=authorization_code";

            String accessTokenUrl = String.format(baseAccessTokenUrl,
                    ConstantWxUtils.WX_OPEN_APP_ID, //id和密钥注入
                    ConstantWxUtils.WX_OPEN_APP_SECRET,
                    code);

            //2.使用httpclient发送请求,得到返回结果
            String accessTokenInfo = HttpClientUtils.get(accessTokenUrl);

            //3.将accessTokenInfo中的信息取出来,(将里面字符串转为map集合,根据map里面key获取对应值)
            Gson gson = new Gson();
            HashMap mapAcessToken = gson.fromJson(accessTokenInfo, HashMap.class);
            String access_token = (String) mapAcessToken.get("access_token");
            String openid = (String) mapAcessToken.get("openid");

            //4.根据openid对数据库进行查询
            UcenterMember member=memberService.getOpenIdMember(openid);

            if(member==null){
                //5.拿着access_token访问凭证和openid去请求微信提供的固定地址,获取扫描人的信息
                String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
                        "?access_token=%s" +
                        "&openid=%s";
                String userInfoUrl = String.format(
                        baseUserInfoUrl,
                        access_token,
                        openid
                );

                //6.发送请求得到用户结果
                String userInfo = HttpClientUtils.get(userInfoUrl);
                System.out.println("userInfo:"+userInfo);

                //7.捕获userInfo中人物信息:名字和头像
                HashMap userInfoMap = gson.fromJson(userInfo, HashMap.class);
                String nickname = (String) userInfoMap.get("nickname");
                String headimgurl = (String) userInfoMap.get("headimgurl");

                //8.说明表中没有相同数据
                member = new UcenterMember();
                member.setOpenid(openid);
                member.setNickname(nickname);
                member.setAvatar(headimgurl);
                memberService.save(member);
            }

            //9.使用jwt根据member的id和name生成token字符串->解决跨域问题,之后的验证直接判断请求头token就好
            String jwtToken = JwtUtils.getJwtToken(member.getId(), member.getNickname());

            return "redirect:http://localhost:3000?token="+jwtToken;
        } catch (Exception e) {
            throw new GuliException(20001,"登陆失败");
        }
    }

第七步:我们利用memberId和memberName生成token,利用token进行访问(不用cookie是因为无法实现跨域,前端给cookie值设置了domain,所以前台拿不到后台的数据,因为有两个域名一个前台的服务一个后台的服务)

利用token我们再将token解析就能找到我们要的数据了

 第八步:我们从header中将token取出来然后解析放到cookie中,因为前端我们这里有cookie拦截器

根据this.$route.query.token取得token值,根据token获得用户信息回显到前端

 /**
     * 3.根据token获取用户信息
     */
    @GetMapping("getMemberInfo")
    public R getMemberInfo(HttpServletRequest request){
        //getMemberIdByJwtToken根据请求头中的token得到用户信息(token得到userid->取出信息)
        String memberId = JwtUtils.getMemberIdByJwtToken(request);
        //根据用户id查询用户信息
        UcenterMember member = memberService.getById(memberId);
        return R.ok().data("userInfo",member);
    }

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fairy要carry

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值