一、网关鉴权
1、问题
当我们在未登录状态下点击“购买课程”按钮时,会显示“未知错误”,查看trade微服务控制台,发现控制台中报错,提示JWT为空,无法鉴权。
2、解决方案
微服务网关中添加自定义全局过滤器,统一处理需要鉴权的服务
3、鉴权逻辑描述
- 当客户端第一次请求服务时,服务端对用户进行信息认证(登录)
- 认证通过,将用户信息进行加密形成token,返回给客户端
- 作为登录凭证以后每次请求,客户端都携带认证的token
- 服务端对token进行解密,判断是否有效
对于验证用户是否已经登录鉴权的过程可以在网关统一检验。检验的标准就是请求中是否携带token凭证以及token的正确性。
下面的我们自定义一个GlobalFilter,去校验所有的请求参数中是否包含“token”,如何不包含请求
参数“token”则不转发路由,否则执行正常的逻辑。
二、开发鉴权逻辑
1、网关中添加依赖
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>common_util</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!--排除spring-boot-starter-web,否则和gateway中的webflux冲突-->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--将随着spring-boot-starter-web排除的servlet-api添加回来 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!--gson-->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
2、排除数据源自动配置
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
3、创建过滤器
package com.atguigu.guli.infrastructure.apigateway.filter;
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
//谷粒学院api接口,校验用户必须登录
AntPathMatcher antPathMatcher = new AntPathMatcher();
if(antPathMatcher.match("/api/**/auth/**", path)) {
List<String> tokenList = request.getHeaders().get("token");
//没有token
if(null == tokenList) {
ServerHttpResponse response = exchange.getResponse();
return out(response);
}
//token校验失败
Boolean isCheck = JwtUtils.checkJwtTToken(tokenList.get(0));
if(!isCheck) {
ServerHttpResponse response = exchange.getResponse();
return out(response);
}
}
//放行
return chain.filter(exchange);
}
//定义当前过滤器的优先级,值越小,优先级越高
@Override
public int getOrder() {
return 0;
}
private Mono<Void> out(ServerHttpResponse response) {
JsonObject message = new JsonObject();
message.addProperty("success", false);
message.addProperty("code", 28004);
message.addProperty("data", "");
message.addProperty("message", "鉴权失败");
byte[] bytes = message.toString().getBytes(StandardCharsets.UTF_8);
DataBuffer buffer = response.bufferFactory().wrap(bytes);
//指定编码,否则在浏览器中会中文乱码
response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
//输出http响应
return response.writeWith(Mono.just(buffer));
}
}
测试:在未登录状态下点击立即购买显示“鉴权失败”。
4、前端修改
guli-site的utils/request.js中修改响应过滤器 ,添加分支:
else if (res.code === 28004) { // 鉴权失败
window.location.href = '/login'
return
}
修改pages/login.vue的submitLogin方法:登录后回到原来的页面
// 跳转到首页
// window.location.href = '/'
if (document.referrer.indexOf('register') !== -1) {
window.location.href = '/'
} else {
history.go(-1)
}