阅读完需:约 3 分钟
依旧是基于授权码模式改造:
前面我们所写的第三方登录,我们在 Controller 中是这么定义的: (client-app 中的HelloController文件)
@GetMapping("/index.html")
public String index2(String code , Model model){
if(code!=null){
System.out.println(code);
//一个key对应多个value,通常我们会将多个value放到一个集合中
MultiValueMap<String,String> map=new LinkedMultiValueMap();
map.add("code",code);
map.add("client_id","xjh");
map.add("client_secret","123");
map.add("redirect_uri","http://localhost:8082/index.html");
map.add("grant_type","authorization_code");
Map<String,String> resp = restTemplate.postForObject("http://localhost:8080/oauth/token", map, Map.class);
System.out.println("resp="+resp);
HttpHeaders headers=new HttpHeaders();
headers.add("Authorization","Bearer"+resp.get("access_token"));
HttpEntity<?> httpEntity=new HttpEntity<>(headers);
ResponseEntity<String> responseEntity = restTemplate.exchange("http://localhost:8081/hello", HttpMethod.GET, httpEntity, String.class);
model.addAttribute("msg",responseEntity.getBody());
}
return "index";
}
我们可以封装优化一下:
首先我们来定义一个专门的类 TokenTask 用来解决 Token 的管理问题:
TokenTask
@Component
public class TokenTask {
@Autowired
RestTemplate restTemplate;
public String access_token="";
public String refresh_token="";
/**
* 刚拿到授权码去申请令牌
*/
public String getData(String code) {
if ("".equals(access_token) && code != null) {
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.add("code", code);
map.add("client_id", "xjh");
map.add("client_secret", "123");
map.add("redirect_uri", "http://localhost:8082/index.html");
map.add("grant_type", "authorization_code");
Map<String, String> resp = restTemplate.postForObject("http://localhost:8080/oauth/token", map, Map.class);
access_token = resp.get("access_token");
refresh_token = resp.get("refresh_token");
}
return loadDataFromResServer();
}
/**
* 通过令牌去申请资源
* @return 返回资源的内容
*/
private String loadDataFromResServer() {
try {
HttpHeaders headers=new HttpHeaders();
headers.add("Authorization","Bearer"+access_token);
HttpEntity<Object> httpEntity=new HttpEntity<>(headers);
ResponseEntity<String> entity = restTemplate.exchange("http://localhost:8081/hello", HttpMethod.GET, httpEntity, String.class);
return entity.getBody();
}catch (Exception e){
return "未加载";
}
}
/**
* 定时去刷新令牌
*/
@Scheduled(cron = "0 55 0/1 * * ?")
public void tokenTask(){
MultiValueMap<String,String> map=new LinkedMultiValueMap<>();
map.add("client_id","xjh");
map.add("client_secret","123");
map.add("grant_type","refresh_token");
map.add("refresh_token",refresh_token);
Map<String,String> resp = restTemplate.postForObject("http://localhost:8080/oauth/token", map, Map.class);
access_token=resp.get("access_token");
refresh_token=resp.get("refresh_token");
}
}
这段代码没有技术难点,主要是逻辑上,我稍微解释一下:
- 1. 首先在 getData 方法中,如果 access_token 为空字符串,并且 code 不为 null,表示这是刚刚拿到授权码的时候,准备去申请令牌了,令牌拿到之后,将 access_token 和 refresh_token 分别赋值给全局变量,然后调用 loadDataFromResServer 方法去资源服务器加载数据。
- 2. 另外有一个 tokenTask 方法,这是一个定时任务,每隔 115 分钟去刷新一下access_token(access_token 有效期是 120 分钟)。
改造完成后,我们再去 HelloController 中略作调整:
@Autowired
TokenTask tokenTask;
@GetMapping("/index.html")
public String index(String code , Model model ){
model.addAttribute("msg",tokenTask.getData(code));
return "index";
}
效果和之前的一样,但是不同的是这个页面这次再按F5刷新就不会出错了。