根据第三方用户名密码使用HTTP获取token并存入redis

一、http工具类

package com.shop.ums.config;

import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

import java.io.IOException;

public class HttpRequestUtil {

    private static final OkHttpClient client = new OkHttpClient();
    private static final MediaType JSON = MediaType.get("application/json; charset=utf-8");

    public static String post(String url, String json) throws IOException {
        RequestBody body = RequestBody.create(json, JSON);
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();
        try (Response response = client.newCall(request).execute()) {
            return response.body().string();
        }
    }
}

二、实现方法

  1. 初始化与依赖注入
    • 在应用启动时,Spring容器会创建 SwaggerUserServiceImpl 的实例,并通过构造器注入 RestTemplate 和 StringRedisTemplate 依赖。这些依赖分别用于发起HTTP请求和缓存访问令牌。
    • <dependency>
          <groupId>com.squareup.okhttp3</groupId>
          <artifactId>okhttp</artifactId>
          <version>4.9.0</version> <!-- 使用最新的版本 -->
      </dependency>
  2. 获取访问令牌
    • 在 list() 方法被调用之前,首先会调用 getToken() 方法来尝试获取一个有效的访问令牌。
    • getToken() 方法首先尝试从Redis缓存中检索名为 access_token 的键值。如果找到了令牌并且它仍然有效(尽管在这个示例中我们没有直接检查令牌的有效性,但在实际应用中这是必要的),则直接使用这个令牌。
    • 如果Redis中没有令牌或者令牌被认为已过期,getToken() 方法将调用 refreshToken() 方法来获取一个新的令牌。
  3. 刷新访问令牌
    • refreshToken() 方法负责通过HTTP POST请求向认证服务(如OAuth2授权服务器)发送登录凭据(用户名和密码),以换取一个新的访问令牌。
    • 发送请求前,会构造一个包含登录信息的JSON字符串。然后,使用 HttpRequestUtil.post 方法(尽管这个方法在类中没有定义,但我们可以假设它是一个辅助工具类中的静态方法,用于发送HTTP POST请求)发送请求到认证服务的登录端点。
    • 收到响应后,解析JSON响应体以提取访问令牌,并将其存储在Redis缓存中,设置过期时间为10分钟。这样,后续的请求就可以在缓存中快速获取到令牌,而无需每次都向认证服务发送登录请求。
  4. 调用第三方API获取用户列表
    • 一旦有了有效的访问令牌,list() 方法将继续执行。它构造一个HTTP GET请求,该请求包含必要的授权头(Authorization: Bearer <access_token>),并指向第三方API的用户列表端点。
    • 使用 RestTemplate 的 exchange 方法发送请求,并指定返回类型为 Result<TableDataInfo>,以便Spring能够自动将JSON响应体反序列化为该类型的对象。
    • 最后,list() 方法返回从第三方API检索到的用户列表数据。

三、yml配置文件

third:
    party:
      api:
        url: http://139.224.214.38:8080/system/user1

四、实现方法

package com.shop.ums.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.shop.common.core.domain.Result;
import com.shop.common.core.web.page.TableDataInfo;
import com.shop.ums.config.HttpRequestUtil;
import com.shop.ums.service.SwaggerUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.beans.factory.annotation.Value;

import java.io.IOException;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

/**
 * @Author:luyuhang
 * @Package:com.shop.ums.service.impl
 * @Project:fourproject
 * @name:SwaggerUserServiceImpl
 */
@Service
public class SwaggerUserServiceImpl implements SwaggerUserService {
    private final RestTemplate restTemplate;
    private final StringRedisTemplate redisTemplate;

    @Value("${third.party.api.url}")
    private String apiUrl;
    private String token;

    private static final Logger log = LoggerFactory.getLogger(SwaggerUserServiceImpl.class);
    private String accessToken;

    public SwaggerUserServiceImpl(RestTemplate restTemplate, StringRedisTemplate redisTemplate) {
        this.restTemplate = restTemplate;
        this.redisTemplate = redisTemplate;
    }

    @Override
    public Result<TableDataInfo> list() {
        getToken();

        String url = apiUrl + "/list";
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", "Bearer " + accessToken);
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> entity = new HttpEntity<>(headers);
        ResponseEntity<Result<TableDataInfo>> response = restTemplate.exchange(
                url,
                HttpMethod.GET,
                entity,
                new ParameterizedTypeReference<Result<TableDataInfo>>() {}
        );
        return response.getBody();
    }

    private void getToken() {
        // 尝试从Redis获取token
        accessToken = redisTemplate.opsForValue().get("access_token");
        if (accessToken != null) {
            log.info("获取token值为:{}", accessToken);
            return;
        }
        // 如果没有获取到token,或者token已经过期(这里假设你有一个方法来判断token是否过期),则重新获取
        refreshToken();
    }

    private void refreshToken() {
        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("username", "admin");
        hashMap.put("password", "admin123");

        String url = "http://139.224.214.38:8080/auth/login";
        String json = JSON.toJSONString(hashMap);
        try {
            token = HttpRequestUtil.post(url, json);
            JSONObject jsonObject = JSON.parseObject(token);
            JSONObject dataObject = jsonObject.getJSONObject("data");
            accessToken = dataObject.getString("access_token");
            // 将token存入Redis,设置10分钟有效期
            redisTemplate.opsForValue().set("access_token", accessToken, 10, TimeUnit.MINUTES);
            log.info("Access Token refreshed: {}", accessToken);
        } catch (IOException e) {
            throw new RuntimeException("Failed to refresh access token", e);
        }
    }

}
Java,可以使用拦截器(Interceptor)或过滤器(Filter)来实现在调用接口前和调用接口后的一些操作,比如检查token是否失效或过期,自动刷新token存入Redis。 以下是一个基本的实现过程: 1. 编写拦截器或过滤器,在调用接口前和调用接口后进行操作。 2. 在调用接口前,从Redis获取token,并检查token是否失效或过期。 3. 如果token失效或过期,则根据刷新token的接口重新获取新的token,并将新的token存入Redis。 4. 在调用接口时,将新的token传递给接口。 下面是一个简单的实现示例: ```java public class TokenInterceptor implements HandlerInterceptor { @Autowired private RedisTemplate<String, String> redisTemplate; @Value("${token.expireTime}") private long expireTime; @Value("${token.refreshUrl}") private String refreshUrl; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 从请求头获取token String token = request.getHeader("token"); if (StringUtils.isEmpty(token)) { throw new RuntimeException("token不能为空"); } // 从Redis获取token对应的value值 String value = redisTemplate.opsForValue().get(token); if (StringUtils.isEmpty(value)) { throw new RuntimeException("token已失效,请重新登录"); } // 检查token是否过期 long expire = redisTemplate.getExpire(token, TimeUnit.SECONDS); if (expire <= 0) { // token已过期,重新获取存入Redis String refreshedToken = refresh(token); redisTemplate.opsForValue().set(refreshedToken, value, expireTime, TimeUnit.SECONDS); redisTemplate.delete(token); // 将新的token传递给接口 request.setAttribute("token", refreshedToken); } else { // 将token传递给接口 request.setAttribute("token", token); } return true; } private String refresh(String token) { // 调用刷新token的接口,获取新的token String refreshedToken = restTemplate.getForObject(refreshUrl + "?token=" + token, String.class); if (StringUtils.isEmpty(refreshedToken)) { throw new RuntimeException("刷新token失败"); } return refreshedToken; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // do nothing } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // do nothing } } ``` 在上面的代码,我们定义了一个TokenInterceptor拦截器,并实现了preHandle方法,在该方法进行了token的检查和刷新操作。 我们使用SpringRedisTemplate来操作Redis,其expireTime和refreshUrl是从配置文件读取的参数。如果token失效或过期,则调用refresh方法获取新的token,并将新的token存入Redis,同时将新的token传递给接口。 我们还可以在配置文件配置该拦截器: ```java @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Autowired private TokenInterceptor tokenInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(tokenInterceptor).addPathPatterns("/**"); } } ``` 这样,当我们调用接口时,TokenInterceptor拦截器会自动检查token并刷新token,确保我们的接口调用是有效的。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值