微信小程序获取access_token,并定时刷新

前言

因为微信小程序调用绝大多数后台接口时都需使用 access_token,由于access_token的时限只有2 个小时,需要定时刷新,还需要避免重复刷新access_token导致原有access_token过期。所以使用每隔半个小时获取一次access_token并将获取到的值存到redis中的解决方案,当需要用到该access_token时直接从redis中获取。从而避免多用户重复请求微信获取凭证接口而导致的access_token过期问题。

开始前准备

请求地址

https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

请求参数

属性 类型 必填 说明
grant_type string 填写 client_credential
appid string 小程序唯一凭证,即 AppID
secret string 小程序唯一凭证密钥,即 AppSecret,获取方式同 appid

返回值

属性 类型 说明
access_token string 获取到的凭证
expires_in number 凭证有效时间,单位:秒。目前是7200秒之内的值。
errcode number 错误码
errmsg string 错误信息

返回数据示例

1
2
3
4
5
6
7
8
9
10
11
# 正常返回
{
"access_token":"ACCESS_TOKEN",
"expires_in":7200
}

# 错误时返回
{
"errcode":40013,
"errmsg":"invalid appid"
}

同时还需要准备的是当前小程序的APPID和SECRET

微信公众平台-开发管理-开发设置

代码实现

POM依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<dependencies>
<!-- Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!--Hutool Java工具包-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.0.5</version>
</dependency>

<!--避免写get,set-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>

YAML 配置文件

1
2
3
4
spring:
redis:
host: localhost
port: 6379

配置类

后端使用RestTemplate代发请求,从而获取access_token

1
2
3
4
5
6
7
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}

小程序端相关配置,APPID和APPSECRET即开始前准备从公众平台获取到的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class WechatConfig {
/**
* 微信小程序APPID
*/
public static final String APPID = "APPID";
/**
* 微信小程序APPSECRET
*/
public static final String APPSECRET = "APPSECRET";

/**
* 获取小程序全局唯一后台接口调用凭据(access_token)
*/
public static final String AUTH_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/" +
"token?grant_type=client_credential&appid=" + APPID + "&secret="
+ APPSECRET;
}

工具类

Redis工具类,对RedisTemplate增删改查的简单封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package com.example.demo.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
* redis操作Service的实现类
*/
@Component
public class RedisUtils {
@Autowired
private StringRedisTemplate stringRedisTemplate;

/**
* 存储数据
*
* @param key 键
* @param value 值
*/
public void set(String key, String value) {
stringRedisTemplate.opsForValue().set(key, value);
}

/**
* 获取数据
*
* @param key 键
* @return
*/
public String get(String key) {
return stringRedisTemplate.opsForValue().get(key);
}

/**
* 设置超期时间
*
* @param key 键
* @param expire 过期时间
* @return 是否成功
*/
public boolean expire(String key, long expire) {
return stringRedisTemplate.expire(key, expire, TimeUnit.SECONDS);
}

/**
* 删除数据
*
* @param key 键
*/
public void remove(String key) {
stringRedisTemplate.delete(key);
}
}

微信工具类,对获取access_token的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
@Component
@Slf4j
public class WechatUtils {
@Autowired
private RestTemplate restTemplate;

@Autowired
private RedisUtils redisUtils;

/**
* @Description: 获取access_token,没过半个小时刷新一次
* @Author: zhengyue
* @Date: 2021/2/20 10:31
* @Param:
* @Return:
*/
@Scheduled(cron = "0 0/30 * * * ? ")
// 程序启动执行一次,保证acess_token一开始就存在
@PostConstruct
public void getAccessToken() {
log.info("access_token开始刷新");
String res = restTemplate.getForObject(WechatConfig.AUTH_ACCESS_TOKEN_URL, String.class);
// 正常返回
// {"access_token":"ACCESS_TOKEN","expires_in":7200}
// 错误时返回
// {"errcode":40013,"errmsg":"invalid appid"}
if(!res.contains("access_token")) {
return;
}
String token = new JSONObject(res).get("access_token", String.class);
// 存入redis 有效时间7200s
redisUtils.set("access_token", token);
redisUtils.expire("access_token", 7200);
}
}

控制层接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@RestController
@RequestMapping("wechat")
public class WechatController {
@Autowired
private RedisUtils redisUtils;

@GetMapping("accessToken")
public String accessToken() {
String token = redisUtils.get(Constant.ACCESS_TOKEN);
if(StringUtils.isEmpty(token)) {
return "access_token已过期,检查appid或者secret是否正确";
}
return token;
}
}
如果你觉得有帮助,慷慨如你,可以扫描下面的二维码赞赏一下