前情回顾
上篇文章,我们讲到了为什么要选择JWT来实现统一认证授权,其优点更符合初期项目的形成,同样可以通过双token来增强用户的体验度种种,而这些纸上谈兵式的谈论过去,迎来的就是如何去实现这些。
本篇文章就是告诉大家如何在SpringCloud项目中使用JWT实现统一授权。
使用JWT来加密解密
在集成到SpringCloud项目中之前,我们要先做一些JWT技术的调研,但是要调研到什么程度才能做到集成的基本要素呢?
如果你问我,我会告诉你,最起码也要将JWT的token加密、解密弄清楚,或者是调试成功,才能去进行集成至SpringCloud中。
准备工作
首先我们要先提供一个密钥,通过此密钥来进行加解密。
JWT加密
直接贴代码:
String key = Base64.getEncoder().encodeToString("zhegekeysuibianshejijiuxingkannixinqing".getBytes(Charsets.UTF_8)); //用户信息 Map<String,String> map = new HashMap<>(); map.put("userId","zhangsan"); //加密 SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; byte[] apiKeySecretBytes = Base64.getDecoder().decode(key); Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName()); JwtBuilder builder = Jwts.builder().signWith(signingKey); map.forEach(builder::claim); //输出token System.out.println(builder.compact());
根据上述代码,我们会生成如下图的一大串token。
JWT解密
解密的话,其实就是将token解析出相应的用户信息。
Claims claims = Jwts.parserBuilder().setSigningKey(Base64.getDecoder().decode(JwtUtil.key)).build() .parseClaimsJws(token).getBody(); System.out.println(claims.get("userId"));
可以得到下图:
将JWT集成到Gateway中
登录认证
我们在Controller层书写一个LoginController.java类,在其中书写一个获取token的api接口。
@RestController public class LoginController { @PostMapping("/token") public R<AuthInfo> token(@RequestParam(required = false) String account, @RequestParam(required = false) String password) { Map<String,String> map = new HashMap<>(16); map.put("account", account); map.put("password", password); String token = JwtUtil.createJwt(map); if (userInfo == null || userInfo.getUser() == null || userInfo.getUser().getId() == null) { return R.fail(); } return R.success(token); } }
编写过滤器验证token
既然搞定了登录获取token的api接口,我们就要将所有访问的URL链接进行过滤器中进行过滤。
所以接下来我们来书写一个认证过滤器。
public class AuthFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { String path = exchange.getRequest().getURI().getPath(); ServerHttpResponse resp = exchange.getResponse(); String headerToken = exchange.getRequest().getHeaders().getFirst("auth"); if (StringUtils.isBlank(headerToken)) { return unAuth(resp, "缺失令牌,鉴权失败"); } Claims claims = JwtUtil.parseJWT(headerToken); if (claims == null) { return unAuth(resp, "请求未授权"); } return chain.filter(exchange); } @Override public int getOrder() { return -99; } }
总结
Gateway中集成统一认证授权,是微服务网关中必然要集成的功能之一,重要性不言而喻,希望大家可以有所重视。