一、網關鑒權
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)
}