GateWay网关整合JWT进行认证

GateWay网关整合JWT进行认证

  1. cloud-auth服务:模拟登陆,获取token
  2. cloud-gateway服务:所有请求通过网关

cloud-auth服务里面的模拟登陆的接口

import com.fasterxml.jackson.databind.ObjectMapper;
import com.yixun.cloudauth.domain.Student;
import com.yixun.cloudauth.rest.entity.RestResult;
import com.yixun.cloudauth.rest.entity.RestResultCode;
import com.yixun.cloudauth.rest.generator.RestResultGenerator;
import com.yixun.cloudauth.service.StudentService;
import com.yixun.cloudauth.utils.JwtModel;
import com.yixun.cloudauth.utils.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;

/**
 * @author ma
 * @date 2022/5/12
 */
@RestController
@Slf4j
@RequestMapping("/auth")
public class AuthController {

    @Autowired
    private StudentService studentService;

    private ObjectMapper objectMapper;

    @Value("1h")
    private String effectiveTime;

    public AuthController(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @PostMapping("/login")
    public RestResult<String> login(@RequestBody Student student) throws Exception {
        //判断登陆的用户信息是否正确
        RestResult<Student> studentByName = studentService.findStudentByName(student.getSname());

        if(studentByName==null || !studentByName.getBody().getData().getPassword().equals(student.getPassword())){
            return RestResultGenerator.failure("用户名与密码不正确");
        }
        ArrayList<String> roleIdList = new ArrayList<>(1);
        roleIdList.add("role_test_1");
        JwtModel jwtModel = new JwtModel(student.getSname(),"000000",roleIdList);
        int effectivTimeInt = Integer.valueOf(effectiveTime.substring(0,effectiveTime.length()-1));
        String effectivTimeUnit = effectiveTime.substring(effectiveTime.length()-1,effectiveTime.length());
        String jwt = null;
        switch (effectivTimeUnit){
            case "s" :{
                //秒
                jwt = JwtUtil.createJWT("test", "test", objectMapper.writeValueAsString(jwtModel), effectivTimeInt * 1000L);
                break;
            }
            case "m" :{
                //分钟
                jwt = JwtUtil.createJWT("test", "test", objectMapper.writeValueAsString(jwtModel), effectivTimeInt * 60L * 1000L);
                break;
            }
            case "h" :{
                //小时
                jwt = JwtUtil.createJWT("test", "test", objectMapper.writeValueAsString(jwtModel), effectivTimeInt * 60L * 60L * 1000L);
                break;
            }
            case "d" :{
                //小时
                jwt = JwtUtil.createJWT("test", "test", objectMapper.writeValueAsString(jwtModel), effectivTimeInt * 24L * 60L * 60L * 1000L);
                break;
            }
        }
        return RestResultGenerator.success("认证成功",jwt);
    }
  }

cloud-gateway服务里面的认证过滤器

/**
 * @author ma
 * @date 2022/5/12
 */
@Component
@Setter
@Getter
@Slf4j
public class JwtTokenFilter implements GlobalFilter, Ordered {

    private ObjectMapper objectMapper;

    public JwtTokenFilter(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        String url = exchange.getRequest().getURI().getPath();

        //跳过不需要验证的路径
        //可以在配置文件中配置该路径
        String skipAuthUrls = "/cloud-auth/auth/login";
        String skip1 = "/cloud-student/v2/api-docs";
        String skip2 = "/cloud-class/v2/api-docs";

        if(skipAuthUrls.equals(url) || skip1.equals(url) || skip2.equals(url)){
            return chain.filter(exchange);
        }
        //获取token
        String token = exchange.getRequest().getHeaders().getFirst("Authorization");
        ServerHttpResponse resp = exchange.getResponse();
        if(StringUtils.isBlank(token)){
            //没有token
            return authErro(resp,"请先认证");
        }else{
            //有token
            try {
                if(JwtUtil.checkToken(token,objectMapper)) {
                    return chain.filter(exchange);
                }else{
                    return authErro(resp,"认证失败");
                }
            }catch (ExpiredJwtException e){
                log.error(e.getMessage(),e);
                if(e.getMessage().contains("Allowed clock skew")){
                    return authErro(resp,"认证过期");
                }else{
                    return authErro(resp,"认证失败");
                }
            }catch (Exception e) {
                log.error(e.getMessage(),e);
                return authErro(resp,"认证失败");
            }

        }
    }

    private Mono<Void> authErro(ServerHttpResponse resp, String mess) {
        resp.setStatusCode(HttpStatus.UNAUTHORIZED);
        resp.getHeaders().add("Content-Type","application/json;charset=UTF-8");
        RestResult<Object> failure = RestResultGenerator.failure(RestResultCode.AUTHORIZATION_CODE_NOT_FOUND, mess);
        String returnStr = "";
        try {
            returnStr = objectMapper.writeValueAsString(failure);
        } catch (JsonProcessingException e) {
            log.error(e.getMessage(),e);
        }
        DataBuffer buffer = resp.bufferFactory().wrap(returnStr.getBytes(StandardCharsets.UTF_8));

        return resp.writeWith(Flux.just(buffer));
    }

    @Override
    public int getOrder() {
        return -100;
    }
}

实现效果

  • 调用cloud-auth服务中的login接口,获取到对应的token
    在这里插入图片描述
  • 请求其他为放行路径的时候,提示认证过期
    在这里插入图片描述
  • 在请求头加入对应的token信息后,请求成功访问
    在这里插入图片描述

JWT的工具类

/**
 * @author ma
 * @date 2022/5/12
 */
@Slf4j
public class JwtUtil {

    @Autowired
    private RestTemplate restTemplate;

    public static final String KEY = "xiaoma";

    /**
     * 由字符串生成加密key
     *
     * @return
     */
    public static SecretKey generalKey(){
        byte[] encodedKey = Base64.decodeBase64(KEY);
        SecretKeySpec key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");

        return key;
    }

    public static String createJWT(String id, String issuer, String subject, long ttlMillis) throws Exception {

        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

        // 生成JWT的时间
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);

        Map<String, Object> claims = new HashMap<>();
        claims.put("uid", "123456");
        claims.put("user_name", "admin");
        claims.put("nick_name", "X-rapido");

        SecretKey key = generalKey();

        JwtBuilder builder = Jwts.builder()
                .setClaims(claims)
                .setId(id)
                .setIssuedAt(now)
                .setIssuer(issuer)
                .setSubject(subject)
                .signWith(signatureAlgorithm, key);

        // 设置过期时间
        if (ttlMillis >= 0) {
            long expMillis = nowMillis + ttlMillis;
            Date exp = new Date(expMillis);
            builder.setExpiration(exp);
        }
        return builder.compact();
    }

    public static Claims parseJWT(String jwt) throws Exception {
        SecretKey key = generalKey();
        Claims claims = Jwts.parser()
                .setSigningKey(key)
                .parseClaimsJws(jwt).getBody();
        return claims;
    }


    public static boolean checkToken(String jwtToken, ObjectMapper objectMapper) throws Exception {
        //TODO 根据自己的业务修改
        //解析token的时候,过期了会抛出异常
        Claims claims = JwtUtil.parseJWT(jwtToken);
        String subject = claims.getSubject();
        JwtModel jwtModel = objectMapper.readValue(subject, JwtModel.class);
        /*
            TODO 对jwt里面的用户信息做判断
            根据自己的业务编写
            在jwtModel取登陆的用户信息,与当前登陆的用户信息进行比较
         */
        String tokenUsername = jwtModel.getUserName();
        /*
            获取token的过期时间,和当前时间作比较,如果小于当前时间,则token过期
         */
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
        Date expiration = claims.getExpiration();
        return true;
    }
}
/**
 * @author ma
 * @date 2022/5/12
 */
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class JwtModel {

    private String userName;

    private String password;

    private List<String> roleIdList;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小马爱打代码

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

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

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

打赏作者

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

抵扣说明:

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

余额充值