实现微信授权认证过程/步骤

时间:2024-03-02 18:52:09

GitHub:https://github.com/JDawnF

最近在做个项目是基于微信的,所以去查看了微信开发文档。

具体而言,网页授权流程分为四步:

1 第一步:用户同意授权,获取code

2 第二步:通过code换取网页授权access_token

3 第三步:刷新access_token(如果需要)

4 第四步:拉取用户信息(需scope为 snsapi_userinfo)

5 附:检验授权凭证(access_token)是否有效


  第一步:修改授权url:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect 其中将appid,direct_uri需要换成自己公众号的;
    direct_uri是授权后重定向的回调链接地址,请使用 urlEncode(转换,避免乱码,Java中是URLEncoder这个类) 对链接进行处理
    scope:应用授权作用域,snsapi_base(不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息 )
    如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE。
    code说明:code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。

  第二步:通过code换取网页授权access_token
      这里通过code换取的是一个特殊的网页授权access_token,与基础支持中的access_token(该access_token用于调用其他接口)不同。公众号可通过下述接口来获取网页授权access_token。如果网页授权的作用域为snsapi_base,则本步骤中获取到网页授权access_token的同时,也获取到了openid,snsapi_base式的网页授权流程即到此为止。
      尤其注意:由于公众号的secret和获取到的access_token安全级别都非常高,必须只保存在服务器,不允许传给客户端。后续刷新access_token、通过access_token获取用户信息等步骤,也必须从服务器发起。      获取code后,请求以下链接获取access_token:  https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
      正确返回json格式数据为:
          {

          "access_token":"ACCESS_TOKEN",
          "expires_in":7200,
          "refresh_token":"REFRESH_TOKEN",
          "openid":"OPENID",
          "scope":"SCOPE" 
        }

   第三步:刷新access_token(如果需要)
         由于access_token拥有较短的有效期,当access_token超时后,可以使用refresh_token进行刷新,refresh_token有效期为30天,当refresh_token失效之后,需要用户重新授权。

         获取第二步的refresh_token后,请求以下链接获取access_token:
  https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN
 

第四步:拉取用户信息(需scope为 snsapi_userinfo)

如果网页授权作用域为snsapi_userinfo,则此时开发者可以通过access_token和openid拉取用户信息了。

请求方法:

http:GET(请使用https协议) https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN

 

总而言之,就是先获取code,然后通过这个code去换取access_token,然后通过这个access_token就可以获取到用户的openId了。下面是基于Java的具体实现过程,有两种方式,第一种是手动获取openId,第二种是通过第三方sdk获取openId:

手动获取openId,将openid和SECRET换成自己对应的即可。:

@RestController
@RequestMapping("/weixin")
@Slf4j
public class WeiXinController {
    //微信授权认证登录
    @GetMapping("/auth")
    public void auth(@RequestParam("code") String code) {
        log.info("进入auth方法");
        log.info("code={}", code);
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code="+ code + "&grant_type=authorization_code";
//      调用rest服务,面向的是资源而不是面向服务,都是对应HTTP方法
//      这里的getForObject()是发送一个HTTP GET请求,返回的请求体将映射为一个对象
        RestTemplate restTemplate = new RestTemplate();
        String response = restTemplate.getForObject(url, String.class);
        log.info("response={}", response);
    }
}

调用第三方sdk:

  • 引入maven依赖
<!--sdk获取openid-->
        <dependency>
            <groupId>com.github.binarywang</groupId>
            <artifactId>weixin-java-mp</artifactId>
            <version>2.7.0</version>
        </dependency>

我这里用的springboot,所以需要在配置文件application.yml中加入appid和secret,然后再写一个类注入:

@Data
@Component
//注入application.yml中的属性,前缀为"wechat"
@ConfigurationProperties(prefix = "wechat")
public class WeChatAccountConfig {
    /**
     * 公众平台id
     */
    private String mpAppId;

    /**
     * 公众平台密钥
     */
    private String mpAppSecret;
}

然后再通过第三方sdk提供的方法获取这些属性:

@Component
public class WeChatMpConfig {
//    注入appid和AppSecret
    @Autowired
    private WeChatAccountConfig accountConfig;
//    @Bean主要用于方法上,表示将这个id注入到spring容器中
    @Bean
    public WxMpService wxMpService() {
        WxMpService wxMpService = new WxMpServiceImpl();
        //获取注入的WxMpInMemoryConfigStorage的属性
        wxMpService.setWxMpConfigStorage(wxMpConfigStorage());
        return wxMpService;
    }

    @Bean
    public WxMpConfigStorage wxMpConfigStorage() {
        WxMpInMemoryConfigStorage wxMpConfigStorage = new WxMpInMemoryConfigStorage();
        //获取注入的WeChatAccountConfig属性
        wxMpConfigStorage.setAppId(accountConfig.getMpAppId());
        wxMpConfigStorage.setSecret(accountConfig.getMpAppSecret());
        return wxMpConfigStorage;
    }
}

这里贴一下几个用的方法,看到就可以懂了

最后是controller实现:

@Controller
@RequestMapping("/wechat")
@Slf4j
public class WeChatController {
    @Autowired
    private WxMpService wxMpService;

    @GetMapping("/authorize")
//    传入一个回调url,后面可以实现重定向
    public String authorize(@RequestParam("returnUrl") String returnUrl)  {
        //WxMpService wxMpService = new WxMpServiceImpl();
        //1.配置
        //2.调用方法
//        外网ip
        String url = 外网ip;
        // URLEncoder.encode设置转码,防止url乱码
        String redirectUrl = wxMpService.oauth2buildAuthorizationUrl(url, WxConsts.OAUTH2_SCOPE_BASE,
                URLEncoder.encode(returnUrl));
        log.info("【微信网页授权】获取code,result={}", redirectUrl);
        return "redirect:" + redirectUrl;
    }
//获取code,并交换AccessToken
    @GetMapping("/userInfo")
    public String userInfo(@RequestParam("code") String code,
                           @RequestParam("state") String returnUrl) {
        WxMpOAuth2AccessToken wxMpOAuth2AccessToken = new WxMpOAuth2AccessToken();
        try {
            wxMpOAuth2AccessToken = wxMpService.oauth2getAccessToken(code);
        } catch (WxErrorException e) {
            log.error("【微信网页授权】{}", e);
            throw new SellException(ResultEnum.WECHAT_MP_ERROR.getCode(), e.getError().getErrorMsg());
        }
        String openId = wxMpOAuth2AccessToken.getOpenId();
        return "redirect:" + returnUrl + "?openid=" + openId;
    }
}

同样,贴出部分源码: