045 用戶登陸功能01----JWT和後臺代碼

(1)有狀態登陸概述html

有狀態服務,即服務端須要記錄每次會話的客戶端信息,從而識別客戶端身份,根據用戶身份進行請求的處理,典型的設計如tomcat中的session。java

例如登陸:用戶登陸後,咱們把登陸者的信息保存在服務端session中,而且給用戶一個cookie值,記錄對應的session。而後下次請求,用戶攜帶cookie值來,咱們就能識別到對應session,從而找到用戶的信息。nginx

缺點是什麼?web

  • 服務端保存大量數據,增長服務端壓力ajax

  • 服務端保存用戶狀態,沒法進行水平擴展算法

  • 客戶端請求依賴服務端,屢次請求必須訪問同一臺服務器spring

(2)無狀態登陸概述數據庫

微服務集羣中的每一個服務,對外提供的都是Rest風格的接口。而Rest風格的一個最重要的規範就是:服務的無狀態性,即:apache

  • 服務端不保存任何客戶端請求者信息json

  • 客戶端的每次請求必須具有自描述信息,經過這些信息識別客戶端身份

帶來的好處是什麼呢?

  • 客戶端請求不依賴服務端的信息,任何屢次請求不須要必須訪問到同一臺服務

  • 服務端的集羣和狀態對客戶端透明

  • 服務端能夠任意的遷移和伸縮

  • 減少服務端存儲壓力

(3)實現無狀態

無狀態登陸的流程:

  • 當客戶端第一次請求服務時,服務端對用戶進行信息認證(登陸)

  • 認證經過,將用戶信息進行加密造成token,返回給客戶端,做爲登陸憑證

  • 之後每次請求,客戶端都攜帶認證的token

  • 服務的對token進行解密,判斷是否有效。

流程圖:

 

整個登陸過程當中,最關鍵的點是什麼?

token的安全性

token是識別客戶端身份的惟一標示,若是加密不夠嚴密,被人僞造那就完蛋了。

採用何種方式加密纔是安全可靠的呢?

咱們將採用JWT + RSA非對稱加密

(4)JWT

<1>簡介

JWT,全稱是Json Web Token, 是JSON風格輕量級的受權和身份認證規範,可實現無狀態、分佈式的Web應用受權;官網:https://jwt.io

<2>數據格式

JWT包含三部分數據:

  • Header:頭部,一般頭部有兩部分信息:

    • 聲明類型,這裏是JWT

    咱們會對頭部進行base64編碼,獲得第一部分數據

  • Payload:載荷,就是有效數據,通常包含下面信息:

    • 用戶身份信息(注意,這裏由於採用base64編碼,可解碼,所以不要存放敏感信息)

    • 註冊聲明:如token的簽發時間,過時時間,簽發人等

    這部分也會採用base64編碼,獲得第二部分數據

  • Signature:簽名,是整個數據的認證信息。通常根據前兩步的數據,再加上服務的的密鑰(secret)(不要泄漏,最好週期性更換),經過加密算法生成。用於驗證整個數據完整和可靠性

生成的數據格式:token==我的證件 jwt=我的身份證

能夠看到分爲3段,每段就是上面的一部分數據

<3>JWT交互流程

流程圖:

 

 

 

步驟翻譯:

  • 一、用戶登陸

  • 二、服務的認證,經過後根據secret生成token

  • 三、將生成的token返回給瀏覽器

  • 四、用戶每次請求攜帶token

  • 五、服務端利用公鑰解讀jwt簽名,判斷簽名有效後,從Payload中獲取用戶信息

  • 六、處理請求,返回響應結果

由於JWT簽發的token中已經包含了用戶的身份信息,而且每次請求都會攜帶,這樣服務的就無需保存用戶信息,甚至無需去數據庫查詢,徹底符合了Rest的無狀態規範。

<4>非對稱加密

加密技術是對信息進行編碼和解碼的技術,編碼是把原來可讀信息(又稱明文)譯成代碼形式(又稱密文),其逆過程就是解碼(解密),加密技術的要點是加密算法,加密算法能夠分爲三類:

  • 對稱加密,如AES

    • 基本原理:將明文分紅N個組,而後使用密鑰對各個組進行加密,造成各自的密文,最後把全部的分組密文進行合併,造成最終的密文。

    • 優點:算法公開、計算量小、加密速度快、加密效率高

    • 缺陷:雙方都使用一樣密鑰,安全性得不到保證

  • 非對稱加密,如RSA

    • 基本原理:同時生成兩把密鑰:私鑰和公鑰,私鑰隱祕保存,公鑰能夠下發給信任客戶端

      • 私鑰加密,持有私鑰或公鑰才能夠解密

      • 公鑰加密,持有私鑰纔可解密

    • 優勢:安全,難以破解

    • 缺點:算法比較耗時

  • 不可逆加密,如MD5,SHA

    • 基本原理:加密過程當中不須要使用密鑰,輸入明文後由系統直接通過加密算法處理成密文,這種加密後的數據是沒法被解密的,沒法根據密文推算出明文。

RSA算法歷史:

1977年,三位數學家Rivest、Shamir 和 Adleman 設計了一種算法,能夠實現非對稱加密。這種算法用他們三我的的名字縮寫:RSA

<5>結合Zuul的鑑權流程

 

  • 咱們首先利用RSA生成公鑰和私鑰。私鑰保存在受權中心,公鑰保存在Zuul和各個信任的微服務

  • 用戶請求登陸

  • 受權中心校驗,經過後用私鑰對JWT進行簽名加密

  • 返回jwt給用戶

  • 用戶攜帶JWT訪問

  • Zuul直接經過公鑰解密JWT,進行驗證,驗證經過則放行

  • 請求到達微服務,微服務直接用公鑰解析JWT,獲取用戶信息,無需訪問受權中心

2.受權中心

(1)建立受權中心

受權中心的主要職責:

  • 用戶鑑權:

    • 接收用戶的登陸請求,經過用戶中心的接口進行校驗,經過後生成JWT

    • 使用私鑰生成JWT並返回

  • 服務鑑權:微服務間的調用不通過Zuul,會有風險,須要鑑權中心進行認證

    • 原理與用戶鑑權相似,但邏輯稍微複雜一些(此處咱們不作實現)

由於生成jwt,解析jwt這樣的行爲之後在其它微服務中也會用到,所以咱們會抽取成工具。咱們把鑑權中心進行聚合,一個工具module,一個提供服務的module

<1>建立父module

 咱們先建立父module(maven模塊),名稱爲:leyou-auth

 

pom文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>leyou</artifactId>
        <groupId>lucky.leyou.parent</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <packaging>pom</packaging>
    
    <groupId>lucky.leyou.auth</groupId>
    <artifactId>leyou-auth</artifactId>


</project>

注意:將pom打包方式改成pom

<2>通用module

而後是受權服務的通用模塊:leyou-auth-common:

 

pom文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>leyou-auth</artifactId>
        <groupId>lucky.leyou.auth</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>lucky.leyou.auth</groupId>
    <artifactId>leyou-auth-common</artifactId>


</project>

結構:

<3>受權服務

 

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>leyou-auth</artifactId>
        <groupId>lucky.leyou.auth</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>lucky.leyou.auth</groupId>
    <artifactId>leyou-auth-service</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>lucky.leyou.auth</groupId>
            <artifactId>leyou-auth-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>lucky.leyou.common</groupId>
            <artifactId>leyou-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>

</project>

引導類:

package lucky.leyou;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class LeyouAuthApplication {

    public static void main(String[] args) {
        SpringApplication.run(LeyouAuthApplication.class, args);
    }
}

application.yml:

server:
  port: 8090
spring:
  application:
    name: auth-service
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
    registry-fetch-interval-seconds: 10
  instance:
    lease-renewal-interval-in-seconds: 5 # 每隔5秒發送一次心跳
    lease-expiration-duration-in-seconds: 10 # 10秒不發送就過時

結構:

在leyou-gateway工程的application.yml中,修改路由:

zuul:
  prefix: /api # 路由路徑前綴
  routes:
    item-service: /item/** # 商品微服務的映射路徑
    search-service: /search/** # 搜索微服務
    user-service: /user/** # 用戶微服務
    auth-service: /auth/** # 受權中心微服務

(2)JWT工具類

咱們在leyou-auth-common中導入課前資料中的工具類:

 

須要在leyou-auth-common中引入JWT依賴:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>leyou-auth</artifactId>
        <groupId>lucky.leyou.auth</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>lucky.leyou.auth</groupId>
    <artifactId>leyou-auth-common</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
        </dependency>
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
        </dependency>
    </dependencies>


</project>

 (3)測試工具類

咱們在leyou-auth-common中編寫測試類:

 

package lucky.leyou.auth.test;

import lucky.leyou.auth.entity.UserInfo;
import lucky.leyou.auth.utils.JwtUtils;
import lucky.leyou.auth.utils.RsaUtils;
import org.junit.Before;
import org.junit.Test;

import java.security.PrivateKey;
import java.security.PublicKey;

public class JwtTest {

    private static final String pubKeyPath = "C:\\tmp\\rsa\\rsa.pub";

    private static final String priKeyPath = "C:\\tmp\\rsa\\rsa.pri";

    private PublicKey publicKey;

    private PrivateKey privateKey;

    @Test
    public void testRsa() throws Exception {
        RsaUtils.generateKey(pubKeyPath, priKeyPath, "234");
    }

    @Before
    public void testGetRsa() throws Exception {
        this.publicKey = RsaUtils.getPublicKey(pubKeyPath);
        this.privateKey = RsaUtils.getPrivateKey(priKeyPath);
    }

    @Test
    public void testGenerateToken() throws Exception {
        // 生成token
        String token = JwtUtils.generateToken(new UserInfo(20L, "jack"), privateKey, 5);
        System.out.println("token = " + token);
    }

    @Test
    public void testParseToken() throws Exception {
        String token = "eyJhbGciOiJSUzI1NiJ9.eyJpZCI6MjAsInVzZXJuYW1lIjoiamFjayIsImV4cCI6MTUzMzI4MjQ3N30.EPo35Vyg1IwZAtXvAx2TCWuOPnRwPclRNAM4ody5CHk8RF55wdfKKJxjeGh4H3zgruRed9mEOQzWy79iF1nGAnvbkraGlD6iM-9zDW8M1G9if4MX579Mv1x57lFewzEo-zKnPdFJgGlAPtNWDPv4iKvbKOk1-U7NUtRmMsF1Wcg";

        // 解析token
        UserInfo user = JwtUtils.getInfoFromToken(token, publicKey);
        System.out.println("id: " + user.getId());
        System.out.println("userName: " + user.getUsername());
    }
}

<1>測試生成公鑰和私鑰

咱們運行這段代碼:注意須要把@Before方法註釋掉

 

運行以後,查看目標目錄:

公鑰和私鑰已經生成了!

<2>測試生成token

將@Before的註釋去掉:

 控制檯輸出:

<3>測試解析token:

正常狀況:

任意改動token,發現報錯了:

3.編寫登陸受權接口

 

接下來,咱們須要在leyou-auth-servcice編寫一個接口,對外提供登陸受權服務。基本流程以下:

 

  • 客戶端攜帶用戶名和密碼請求登陸

  • 受權中心調用用戶中心接口,根據用戶名和密碼查詢用戶信息

  • 若是用戶名密碼正確,能獲取用戶,不然爲空,則登陸失敗

  • 若是校驗成功,則生成JWT並返回

 邏輯分析圖:

 

(1)生成公鑰和私鑰

咱們須要在受權中心生成真正的公鑰和私鑰。咱們必須有一個生成公鑰和私鑰的secret,這個能夠配置到leyou-auth-service模塊的application.yml中:

 

leyou:
  jwt:
    secret: leyou@Login(Auth}*^31)&heiMa% # 登陸校驗的密鑰
    pubKeyPath: D:\temp\rsa\\rsa.pub # 公鑰地址
    priKeyPath: D:\temp\rsa\\rsa.pri # 私鑰地址
    expire: 30 # 過時時間,單位分鐘

而後編寫屬性類,加載這些數據:

package lucky.leyou.auth.config;

import lucky.leyou.auth.utils.RsaUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import javax.annotation.PostConstruct;
import java.io.File;
import java.security.PrivateKey;
import java.security.PublicKey;

@ConfigurationProperties(prefix = "leyou.jwt")
public class JwtProperties {

    private String secret; // 密鑰

    private String pubKeyPath;// 公鑰路徑

    private String priKeyPath;// 私鑰路徑

    private int expire;// token過時時間

    private PublicKey publicKey; // 公鑰

    private PrivateKey privateKey; // 私鑰

    private static final Logger logger = LoggerFactory.getLogger(JwtProperties.class);

    /**
     * @PostContruct:在構造方法執行以後執行該方法
     */
    @PostConstruct
    public void init(){
        try {
            File pubKey = new File(pubKeyPath);
            File priKey = new File(priKeyPath);
            if (!pubKey.exists() || !priKey.exists()) {
                // 生成公鑰和私鑰
                RsaUtils.generateKey(pubKeyPath, priKeyPath, secret);
            }
            // 獲取公鑰和私鑰
            this.publicKey = RsaUtils.getPublicKey(pubKeyPath);
            this.privateKey = RsaUtils.getPrivateKey(priKeyPath);
        } catch (Exception e) {
            logger.error("初始化公鑰和私鑰失敗!", e);
            throw new RuntimeException();
        }
    }

    // getter setter ...

    public String getSecret() {
        return secret;
    }

    public void setSecret(String secret) {
        this.secret = secret;
    }

    public String getPubKeyPath() {
        return pubKeyPath;
    }

    public void setPubKeyPath(String pubKeyPath) {
        this.pubKeyPath = pubKeyPath;
    }

    public String getPriKeyPath() {
        return priKeyPath;
    }

    public void setPriKeyPath(String priKeyPath) {
        this.priKeyPath = priKeyPath;
    }

    public int getExpire() {
        return expire;
    }

    public void setExpire(int expire) {
        this.expire = expire;
    }

    public PublicKey getPublicKey() {
        return publicKey;
    }

    public void setPublicKey(PublicKey publicKey) {
        this.publicKey = publicKey;
    }

    public PrivateKey getPrivateKey() {
        return privateKey;
    }

    public void setPrivateKey(PrivateKey privateKey) {
        this.privateKey = privateKey;
    }
}

(2)controller

編寫受權接口,咱們接收用戶名和密碼,校驗成功後,寫入cookie中。

  • 請求方式:post

  • 請求路徑:/accredit

  • 請求參數:username和password

  • 返回結果:無

代碼:

這裏的cookie的name和生存時間,咱們配置到屬性文件:application.yml:

leyou:
  jwt:
    secret: leyou@Login(Auth}*^31)&heiMa% # 登陸校驗的密鑰
    pubKeyPath: D:\temp\rsa\\rsa.pub # 公鑰地址
    priKeyPath: D:\temp\rsa\\rsa.pri # 私鑰地址
    expire: 30 # 過時時間,單位分鐘
    cookieName: LY_TOKEN #cookie的名稱
    cookieMaxAge: 30 

而後在JwtProperties中添加屬性,同時生成get和set方法:

代碼:

package lucky.leyou.auth.controller;

import lucky.leyou.auth.config.JwtProperties;
import lucky.leyou.common.utils.CookieUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Controller
@EnableConfigurationProperties(JwtProperties.class)
public class AuthController {

    @Autowired
    private AuthService authService;

    @Autowired
    private JwtProperties prop;

    /**
     * 登陸受權
     *
     * @param username
     * @param password
     * @return
     */
    @PostMapping("accredit")
    public ResponseEntity<Void> authentication(
            @RequestParam("username") String username,
            @RequestParam("password") String password,
            HttpServletRequest request,
            HttpServletResponse response) {
        // 登陸校驗
        String token = this.authService.authentication(username, password);
        if (StringUtils.isBlank(token)) {
            return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
        }
        // 將token寫入cookie,並指定httpOnly爲true,防止經過JS獲取和修改
        CookieUtils.setCookie(request, response, prop.getCookieName(),
                token, prop.getCookieMaxAge(), null, true);
        return ResponseEntity.ok().build();
    }
}

注意:

這裏咱們使用了一個工具類,CookieUtils

(3)UserClient

接下來咱們確定要對用戶密碼進行校驗,因此咱們須要經過FeignClient去訪問 user-service微服務

<1>在leyou-user-interface工程中添加api接口:

 

package lucky.leyou.user.api;

import lucky.leyou.user.domain.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

public interface UserApi {
    /**
     * 根據用戶名和密碼查詢用戶
     * @param username
     * @param password
     * @return
     */
    @GetMapping("query")
    public User queryUser(
            @RequestParam("username") String username,
            @RequestParam("password") String password
    );
}

<2>在leyou-auth-service中編寫FeignClient

在leyou-auth中引入user-service-interface依賴:

<dependency>
            <groupId>lucky.leyou.user</groupId>
            <artifactId>leyou-user-interface</artifactId>
            <version>1.0-SNAPSHOT</version>
</dependency>

參照leyou-search或者leyou-goods-web

package lucky.leyou.auth.client;

import lucky.leyou.user.api.UserApi;
import org.springframework.cloud.openfeign.FeignClient;

@FeignClient(value = "user-service")
public interface UserClient extends UserApi {
}

(4)AuthService

在leyou-auth-service:

package lucky.leyou.auth.service;

import lucky.leyou.auth.client.UserClient;
import lucky.leyou.auth.config.JwtProperties;
import lucky.leyou.auth.entity.UserInfo;
import lucky.leyou.auth.utils.JwtUtils;
import lucky.leyou.user.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class AuthService {

    @Autowired
    private UserClient userClient;

    @Autowired
    private JwtProperties properties;

    public String authentication(String username, String password) {

        try {
            // 調用微服務,執行查詢
            User user = this.userClient.queryUser(username, password);

            // 若是查詢結果爲null,則直接返回null
            if (user == null) {
                return null;
            }

            // 若是有查詢結果,則生成token
            String token = JwtUtils.generateToken(new UserInfo(user.getId(), user.getUsername()),
                    properties.getPrivateKey(), properties.getExpire());
            return token;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

(5)項目完整結構

 

(6)測試

打開postman進行測試:http://localhost:8090/accredit

4.登陸頁面

 

接下來,咱們看看登陸頁面,是否可以正確的發出請求。

 

咱們在頁面輸入登陸信息,而後點擊登陸:

查看控制檯:

發現請求的路徑不對,咱們的認證接口是:

/api/auth/accredit

咱們打開login.html,修改路徑信息:

 

 

頁面ajax請求:

而後再次測試,成功跳轉到了首頁:

5.解決cookie寫入問題

接下來咱們查看首頁cookie:

 

cookie也是有 的限制,一個網頁,只能操做當前域名下的cookie,可是如今咱們看到的地址是0.0.1,而頁面是www.leyou.com,域名不匹配,cookie設置確定失敗了!

(1)跟蹤CookieUtils

咱們去Debug跟蹤CookieUtils,看看究竟是怎麼回事:

咱們發現內部有一個方法,用來獲取Domain:

咱們發現內部有一個方法,用來獲取Domain:

它獲取domain是經過服務器的host來計算的,然而咱們的地址居然是:127.0.0.1:8087,所以後續的運算,最終獲得的domain就變成了:

 

問題找到了:咱們請求時的serverName明明是:api.leyou.com,如今卻被變成了:127.0.0.1,所以計算domain是錯誤的,從而致使cookie設置失敗!

(2)解決host地址的變化

這裏的server name其實就是請求的時的主機名:Host,之因此改變,有兩個緣由:

  • 咱們使用了nginx反向代理,當監聽到api.leyou.com的時候,會自動將請求轉發至127.0.0.1:10010,即Zuul。

  • 然後請求到達咱們的網關Zuul,Zuul就會根據路徑匹配,咱們的請求是/api/auth,根據規則被轉發到了 127.0.0.1:8087 ,即咱們的受權中心。

咱們首先去更改nginx配置,讓它不要修改咱們的host:proxy_set_header Host $host;

 

把nginx進行reload:

nginx -s reload

這樣就解決了nginx這裏的問題。可是Zuul還會有一次轉發,因此要去修改網關的配置(leyou-gateway工程):

zuul:
  prefix: /api # 路由路徑前綴
  routes:
      item-service: /item/**  # 商品微服務的映射路徑
      search-service: /search/** #搜索微服務
      user-service: /user/**  #用戶微服務
      auth-service: /auth/**  # 受權中心微服務
  add-host-header: true #攜帶請求自己的頭信息

重啓後,咱們再次測試。

最終獲得的domainName:

 (3)Zuul的敏感頭過濾

 Zuul內部有默認的過濾器,會對請求和響應頭信息進行重組,過濾掉敏感的頭信息:

會發現,這裏會經過一個屬性爲SensitiveHeaders的屬性,來獲取敏感頭列表,而後添加到IgnoredHeaders中,這些頭信息就會被忽略。

而這個SensitiveHeaders的默認值就包含了set-cookie

 

解決方案:

把敏感頭設置爲null

zuul:
  prefix: /api # 路由路徑前綴
  routes:
      item-service: /item/**  # 商品微服務的映射路徑
      search-service: /search/** #搜索微服務
      user-service: /user/**  #用戶微服務
      auth-service: /auth/**  # 受權中心微服務
  add-host-header: true #攜帶請求自己的頭信息
  sensitive-headers: #覆蓋默認敏感頭信息

(4)測試

相關文章
相關標籤/搜索