{"id":5244,"date":"2022-03-10T22:32:05","date_gmt":"2022-03-10T14:32:05","guid":{"rendered":"http:\/\/123.57.164.21\/?p=5244"},"modified":"2022-03-14T13:47:59","modified_gmt":"2022-03-14T05:47:59","slug":"spring-cloud-gateway%e5%ae%9e%e7%8e%b0token%e6%a0%a1%e9%aa%8c","status":"publish","type":"post","link":"https:\/\/92it.top\/?p=5244","title":{"rendered":"Spring Cloud Gateway\u5b9e\u73b0Token\u6821\u9a8c"},"content":{"rendered":"\n<p>\u5728\u6211\u770b\u6765\uff0c\u5728\u67d0\u4e9b\u573a\u666f\u4e0b\uff0c\u7f51\u5173\u5c31\u50cf\u662f\u4e00\u4e2a\u516c\u5171\u65b9\u6cd5\uff0c\u628a\u9879\u76ee\u4e2d\u7684\u90fd\u8981\u7528\u5230\u7684\u4e00\u4e9b\u529f\u80fd\u63d0\u51fa\u6765\uff0c\u62bd\u8c61\u6210\u4e00\u4e2a\u670d\u52a1\u3002\u6bd4\u5982\uff0c\u6211\u4eec\u53ef\u4ee5\u5728\u4e1a\u52a1\u7f51\u5173\u4e0a\u505a\u65e5\u5fd7\u6536\u96c6\u3001Token\u6821\u9a8c\u7b49\u7b49\uff0c\u5f53\u7136\u8fd9\u4e48\u7406\u89e3\u5f88\u72ed\u9698\uff0c\u56e0\u4e3a\u7f51\u5173\u7684\u80fd\u529b\u8fdc\u4e0d\u6b62\u5982\u6b64\uff0c\u4f46\u662f\u4e0d\u59a8\u788d\u6211\u4eec\u66f4\u597d\u5730\u7406\u89e3\u5b83\u3002\u4e0b\u9762\u7684\u4f8b\u5b50\u6f14\u793a\u4e86\uff0c\u5982\u4f55\u5728\u7f51\u5173\u6821\u9a8cToken\uff0c\u5e76\u63d0\u53d6\u7528\u6237\u4fe1\u606f\u653e\u5230Header\u4e2d\u4f20\u7ed9\u4e0b\u6e38\u4e1a\u52a1\u7cfb\u7edf\u3002<\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>1. \u751f\u6210Token<\/strong><\/h4>\n\n\n\n<p>\u7528\u6237\u767b\u5f55\u6210\u529f\u4ee5\u540e\uff0c\u751f\u6210token\uff0c\u6b64\u540e\u7684\u6240\u6709\u8bf7\u6c42\u90fd\u5e26\u7740token\u3002\u7f51\u5173\u8d1f\u8d23\u6821\u9a8ctoken\uff0c\u5e76\u5c06\u7528\u6237\u4fe1\u606f\u653e\u5165\u8bf7\u6c42Header\uff0c\u4ee5\u4fbf\u4e0b\u6e38\u7cfb\u7edf\u53ef\u4ee5\u65b9\u4fbf\u5730\u83b7\u53d6\u7528\u6237\u4fe1\u606f\u3002<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-34-1024x683.png\" alt=\"\" class=\"wp-image-5245\" width=\"541\" height=\"361\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-34-1024x683.png 1024w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-34-300x200.png 300w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-34-768x512.png 768w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-34-830x553.png 830w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-34-230x153.png 230w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-34-350x233.png 350w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-34-480x320.png 480w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-34.png 1230w\" sizes=\"(max-width: 541px) 100vw, 541px\" \/><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-35-1024x1024.png\" alt=\"\" class=\"wp-image-5246\" width=\"515\" height=\"515\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-35-1024x1024.png 1024w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-35-300x300.png 300w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-35-150x150.png 150w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-35-768x768.png 768w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-35-830x830.png 830w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-35-230x230.png 230w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-35-350x350.png 350w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-35-480x480.png 480w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-35.png 1174w\" sizes=\"(max-width: 515px) 100vw, 515px\" \/><\/figure><\/div>\n\n\n\n<p>\u4e3a\u4e86\u65b9\u4fbf\u6f14\u793a\uff0c\u672c\u4f8b\u4e2d\u6d89\u53ca\u4e09\u4e2a\u5de5\u7a0b<\/p>\n\n\n\n<ul><li>\u516c\u5171\u9879\u76ee\uff1acjs-commons-jwt<\/li><li>\u8ba4\u8bc1\u670d\u52a1\uff1acjs-auth-service<\/li><li>\u7f51\u5173\u670d\u52a1\uff1acjs-gateway-example<\/li><\/ul>\n\n\n\n<h5 class=\"wp-block-heading\"><strong>1.1. Token\u751f\u6210\u4e0e\u6821\u9a8c\u5de5\u5177\u7c7b<\/strong><\/h5>\n\n\n\n<p>\u56e0\u4e3a\u751f\u6210token\u5728\u8ba4\u8bc1\u670d\u52a1\u4e2d\uff0ctoken\u6821\u9a8c\u5728\u7f51\u5173\u670d\u52a1\u4e2d\uff0c\u56e0\u6b64\uff0c\u6211\u628a\u8fd9\u4e00\u90e8\u5206\u5199\u5728\u4e86\u516c\u5171\u9879\u76eecjs-commons-jwt\u4e2d<\/p>\n\n\n\n<p><strong>pom.xml<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> 1 &lt;?xml version=\"1.0\" encoding=\"UTF-8\"?>\n 2 \n 3 &lt;project xmlns=\"http:\/\/maven.apache.org\/POM\/4.0.0\" xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"\n 4   xsi:schemaLocation=\"http:\/\/maven.apache.org\/POM\/4.0.0 http:\/\/maven.apache.org\/xsd\/maven-4.0.0.xsd\">\n 5     &lt;modelVersion>4.0.0&lt;\/modelVersion>\n 6 \n 7     &lt;groupId>com.cjs.example&lt;\/groupId>\n 8     &lt;artifactId>cjs-commons-jwt&lt;\/artifactId>\n 9     &lt;version>1.0-SNAPSHOT&lt;\/version>\n10 \n11     &lt;properties>\n12         &lt;project.build.sourceEncoding>UTF-8&lt;\/project.build.sourceEncoding>\n13         &lt;maven.compiler.source>1.8&lt;\/maven.compiler.source>\n14         &lt;maven.compiler.target>1.8&lt;\/maven.compiler.target>\n15     &lt;\/properties>\n16 \n17     &lt;dependencies>\n18         &lt;dependency>\n19             &lt;groupId>com.auth0&lt;\/groupId>\n20             &lt;artifactId>java-jwt&lt;\/artifactId>\n21             &lt;version>3.10.0&lt;\/version>\n22         &lt;\/dependency>\n23         &lt;dependency>\n24             &lt;groupId>org.apache.commons&lt;\/groupId>\n25             &lt;artifactId>commons-lang3&lt;\/artifactId>\n26             &lt;version>3.9&lt;\/version>\n27         &lt;\/dependency>\n28         &lt;dependency>\n29             &lt;groupId>com.alibaba&lt;\/groupId>\n30             &lt;artifactId>fastjson&lt;\/artifactId>\n31             &lt;version>1.2.66&lt;\/version>\n32         &lt;\/dependency>\n33     &lt;\/dependencies>\n34 \n35 &lt;\/project>\n<\/pre>\n\n\n\n<p><strong>JWTUtil.java<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">1 package com.cjs.example.utils;\n 2 \n 3 import com.auth0.jwt.JWT;\n 4 import com.auth0.jwt.JWTVerifier;\n 5 import com.auth0.jwt.algorithms.Algorithm;\n 6 import com.auth0.jwt.exceptions.JWTDecodeException;\n 7 import com.auth0.jwt.exceptions.SignatureVerificationException;\n 8 import com.auth0.jwt.exceptions.TokenExpiredException;\n 9 import com.auth0.jwt.interfaces.DecodedJWT;\n10 import com.cjs.example.enums.ResponseCodeEnum;\n11 import com.cjs.example.exception.TokenAuthenticationException;\n12 \n13 import java.util.Date;\n14 \n15 \/**\n16  * @author ChengJianSheng\n17  * @date 2020-03-08\n18  *\/\n19 public class JWTUtil {\n20 \n21     public static final long TOKEN_EXPIRE_TIME = 7200 * 1000;\n22     private static final String ISSUER = \"cheng\";\n23 \n24     \/**\n25      * \u751f\u6210Token\n26      * @param username \u7528\u6237\u6807\u8bc6\uff08\u4e0d\u4e00\u5b9a\u662f\u7528\u6237\u540d\uff0c\u6709\u53ef\u80fd\u662f\u7528\u6237ID\u6216\u8005\u624b\u673a\u53f7\u4ec0\u4e48\u7684\uff09\n27      * @param secretKey\n28      * @return\n29      *\/\n30     public static String generateToken(String username, String secretKey) {\n31         Algorithm algorithm = Algorithm.HMAC256(secretKey);\n32         Date now = new Date();\n33         Date expireTime = new Date(now.getTime() + TOKEN_EXPIRE_TIME);\n34 \n35         String token = JWT.create()\n36                 .withIssuer(ISSUER)\n37                 .withIssuedAt(now)\n38                 .withExpiresAt(expireTime)\n39                 .withClaim(\"username\", username)\n40                 .sign(algorithm);\n41 \n42         return token;\n43     }\n44 \n45     \/**\n46      * \u6821\u9a8cToken\n47      * @param token\n48      * @param secretKey\n49      * @return\n50      *\/\n51     public static void verifyToken(String token, String secretKey) {\n52         try {\n53             Algorithm algorithm = Algorithm.HMAC256(secretKey);\n54             JWTVerifier jwtVerifier = JWT.require(algorithm).withIssuer(ISSUER).build();\n55             jwtVerifier.verify(token);\n56         } catch (JWTDecodeException jwtDecodeException) {\n57             throw new TokenAuthenticationException(ResponseCodeEnum.TOKEN_INVALID.getCode(), ResponseCodeEnum.TOKEN_INVALID.getMessage());\n58         } catch (SignatureVerificationException signatureVerificationException) {\n59             throw new TokenAuthenticationException(ResponseCodeEnum.TOKEN_SIGNATURE_INVALID.getCode(), ResponseCodeEnum.TOKEN_SIGNATURE_INVALID.getMessage());\n60         } catch (TokenExpiredException tokenExpiredException) {\n61             throw new TokenAuthenticationException(ResponseCodeEnum.TOKEN_EXPIRED.getCode(), ResponseCodeEnum.TOKEN_INVALID.getMessage());\n62         } catch (Exception ex) {\n63             throw new TokenAuthenticationException(ResponseCodeEnum.UNKNOWN_ERROR.getCode(), ResponseCodeEnum.UNKNOWN_ERROR.getMessage());\n64         }\n65     }\n66 \n67     \/**\n68      * \u4eceToken\u4e2d\u63d0\u53d6\u7528\u6237\u4fe1\u606f\n69      * @param token\n70      * @return\n71      *\/\n72     public static String getUserInfo(String token) {\n73         DecodedJWT decodedJWT = JWT.decode(token);\n74         String username = decodedJWT.getClaim(\"username\").asString();\n75         return username;\n76     }\n77 \n78 }<\/pre>\n\n\n\n<p><strong>ResponseCodeEnum.java<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">1 package com.cjs.example.enums;\n 2 \n 3 \/**\n 4  * @author ChengJianSheng\n 5  * @date 2020-03-08\n 6  *\/\n 7 public enum ResponseCodeEnum {\n 8 \n 9     SUCCESS(0, \"\u6210\u529f\"),\n10     FAIL(-1, \"\u5931\u8d25\"),\n11     LOGIN_ERROR(1000, \"\u7528\u6237\u540d\u6216\u5bc6\u7801\u9519\u8bef\"),\n12     UNKNOWN_ERROR(2000, \"\u672a\u77e5\u9519\u8bef\"),\n13     PARAMETER_ILLEGAL(2001, \"\u53c2\u6570\u4e0d\u5408\u6cd5\"),\n14     TOKEN_INVALID(2002, \"\u65e0\u6548\u7684Token\"),\n15     TOKEN_SIGNATURE_INVALID(2003, \"\u65e0\u6548\u7684\u7b7e\u540d\"),\n16     TOKEN_EXPIRED(2004, \"token\u5df2\u8fc7\u671f\"),\n17     TOKEN_MISSION(2005, \"token\u7f3a\u5931\"),\n18     REFRESH_TOKEN_INVALID(2006, \"\u5237\u65b0Token\u65e0\u6548\");\n19 \n20 \n21     private int code;\n22 \n23     private String message;\n24 \n25     ResponseCodeEnum(int code, String message) {\n26         this.code = code;\n27         this.message = message;\n28     }\n29 \n30     public int getCode() {\n31         return code;\n32     }\n33 \n34     public String getMessage() {\n35         return message;\n36     }\n37 \n38 }<\/pre>\n\n\n\n<p><strong>ResponseResult.java<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">1 package com.cjs.example;\n 2 \n 3 import com.cjs.example.enums.ResponseCodeEnum;\n 4 \n 5 \/**\n 6  * @author ChengJianSheng\n 7  * @date 2020-03-08\n 8  *\/\n 9 public class ResponseResult&lt;T> {\n10 \n11     private int code = 0;\n12 \n13     private String msg;\n14 \n15     private T data;\n16 \n17     public ResponseResult(int code, String msg) {\n18         this.code = code;\n19         this.msg = msg;\n20     }\n21 \n22     public ResponseResult(int code, String msg, T data) {\n23         this.code = code;\n24         this.msg = msg;\n25         this.data = data;\n26     }\n27 \n28     public static ResponseResult success() {\n29         return new ResponseResult(ResponseCodeEnum.SUCCESS.getCode(), ResponseCodeEnum.SUCCESS.getMessage());\n30     }\n31 \n32     public static &lt;T> ResponseResult&lt;T> success(T data) {\n33         return new ResponseResult(ResponseCodeEnum.SUCCESS.getCode(), ResponseCodeEnum.SUCCESS.getMessage(), data);\n34     }\n35 \n36     public static ResponseResult error(int code, String msg) {\n37         return new ResponseResult(code, msg);\n38     }\n39 \n40     public static &lt;T> ResponseResult&lt;T> error(int code, String msg, T data) {\n41         return new ResponseResult(code, msg, data);\n42     }\n43 \n44     public boolean isSuccess() {\n45         return code == 0;\n46     }\n47 \n48     public int getCode() {\n49         return code;\n50     }\n51 \n52     public void setCode(int code) {\n53         this.code = code;\n54     }\n55 \n56     public String getMsg() {\n57         return msg;\n58     }\n59 \n60     public void setMsg(String msg) {\n61         this.msg = msg;\n62     }\n63 \n64     public T getData() {\n65         return data;\n66     }\n67 \n68     public void setData(T data) {\n69         this.data = data;\n70     }\n71 }<\/pre>\n\n\n\n<h5 class=\"wp-block-heading\">1.2. \u751f\u6210token<\/h5>\n\n\n\n<p>\u8fd9\u4e00\u90e8\u5206\u5728cjs-auth-service\u4e2d<\/p>\n\n\n\n<p><strong>pom.xml<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> 1 &lt;?xml version=\"1.0\" encoding=\"UTF-8\"?>\n 2 &lt;project xmlns=\"http:\/\/maven.apache.org\/POM\/4.0.0\" xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"\n 3          xsi:schemaLocation=\"http:\/\/maven.apache.org\/POM\/4.0.0 https:\/\/maven.apache.org\/xsd\/maven-4.0.0.xsd\">\n 4     &lt;modelVersion>4.0.0&lt;\/modelVersion>\n 5     &lt;parent>\n 6         &lt;groupId>org.springframework.boot&lt;\/groupId>\n 7         &lt;artifactId>spring-boot-starter-parent&lt;\/artifactId>\n 8         &lt;version>2.2.5.RELEASE&lt;\/version>\n 9         &lt;relativePath\/> &lt;!-- lookup parent from repository -->\n10     &lt;\/parent>\n11     &lt;groupId>com.cjs.example&lt;\/groupId>\n12     &lt;artifactId>cjs-auth-service&lt;\/artifactId>\n13     &lt;version>0.0.1-SNAPSHOT&lt;\/version>\n14     &lt;name>cjs-auth-service&lt;\/name>\n15 \n16     &lt;properties>\n17         &lt;java.version>1.8&lt;\/java.version>\n18     &lt;\/properties>\n19 \n20     &lt;dependencies>\n21         &lt;dependency>\n22             &lt;groupId>org.springframework.boot&lt;\/groupId>\n23             &lt;artifactId>spring-boot-starter-data-redis&lt;\/artifactId>\n24         &lt;\/dependency>\n25         &lt;dependency>\n26             &lt;groupId>org.springframework.boot&lt;\/groupId>\n27             &lt;artifactId>spring-boot-starter-web&lt;\/artifactId>\n28         &lt;\/dependency>\n29 \n30         &lt;dependency>\n31             &lt;groupId>org.apache.commons&lt;\/groupId>\n32             &lt;artifactId>commons-lang3&lt;\/artifactId>\n33             &lt;version>3.9&lt;\/version>\n34         &lt;\/dependency>\n35         &lt;dependency>\n36             &lt;groupId>commons-codec&lt;\/groupId>\n37             &lt;artifactId>commons-codec&lt;\/artifactId>\n38             &lt;version>1.14&lt;\/version>\n39         &lt;\/dependency>\n40         &lt;dependency>\n41             &lt;groupId>org.apache.commons&lt;\/groupId>\n42             &lt;artifactId>commons-pool2&lt;\/artifactId>\n43             &lt;version>2.8.0&lt;\/version>\n44         &lt;\/dependency>\n45 \n46         &lt;dependency>\n47             &lt;groupId>com.cjs.example&lt;\/groupId>\n48             &lt;artifactId>cjs-commons-jwt&lt;\/artifactId>\n49             &lt;version>1.0-SNAPSHOT&lt;\/version>\n50         &lt;\/dependency>\n51 \n52         &lt;dependency>\n53             &lt;groupId>org.projectlombok&lt;\/groupId>\n54             &lt;artifactId>lombok&lt;\/artifactId>\n55             &lt;optional>true&lt;\/optional>\n56         &lt;\/dependency>\n57     &lt;\/dependencies>\n58 \n59     &lt;build>\n60         &lt;plugins>\n61             &lt;plugin>\n62                 &lt;groupId>org.springframework.boot&lt;\/groupId>\n63                 &lt;artifactId>spring-boot-maven-plugin&lt;\/artifactId>\n64             &lt;\/plugin>\n65         &lt;\/plugins>\n66     &lt;\/build>\n67 \n68 &lt;\/project>\n\n<\/pre>\n\n\n\n<p><strong>LoginController.java<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">1 package com.cjs.example.controller;\n  2 \n  3 import com.cjs.example.ResponseResult;\n  4 import com.cjs.example.domain.LoginRequest;\n  5 import com.cjs.example.domain.LoginResponse;\n  6 import com.cjs.example.domain.RefreshRequest;\n  7 import com.cjs.example.enums.ResponseCodeEnum;\n  8 import com.cjs.example.utils.JWTUtil;\n  9 import org.apache.commons.lang3.StringUtils;\n 10 import org.apache.tomcat.util.security.MD5Encoder;\n 11 import org.springframework.beans.factory.annotation.Autowired;\n 12 import org.springframework.beans.factory.annotation.Value;\n 13 import org.springframework.data.redis.core.HashOperations;\n 14 import org.springframework.data.redis.core.StringRedisTemplate;\n 15 import org.springframework.validation.BindingResult;\n 16 import org.springframework.validation.annotation.Validated;\n 17 import org.springframework.web.bind.annotation.*;\n 18 \n 19 import java.util.UUID;\n 20 import java.util.concurrent.TimeUnit;\n 21 \n 22 \/**\n 23  * @author ChengJianSheng\n 24  * @date 2020-03-08\n 25  *\/\n 26 @RestController\n 27 public class LoginController {\n 28 \n 29     \/**\n 30      * Apollo \u6216 Nacos\n 31      *\/\n 32     @Value(\"${secretKey:123456}\")\n 33     private String secretKey;\n 34 \n 35     @Autowired\n 36     private StringRedisTemplate stringRedisTemplate;\n 37 \n 38     \/**\n 39      * \u767b\u5f55\n 40      *\/\n 41     @PostMapping(\"\/login\")\n 42     public ResponseResult login(@RequestBody @Validated LoginRequest request, BindingResult bindingResult) {\n 43         if (bindingResult.hasErrors()) {\n 44             return ResponseResult.error(ResponseCodeEnum.PARAMETER_ILLEGAL.getCode(), ResponseCodeEnum.PARAMETER_ILLEGAL.getMessage());\n 45         }\n 46 \n 47         String username = request.getUsername();\n 48         String password = request.getPassword();\n 49         \/\/  \u5047\u8bbe\u67e5\u8be2\u5230\u7528\u6237ID\u662f1001\n 50         String userId = \"1001\";\n 51         if (\"hello\".equals(username) &amp;&amp; \"world\".equals(password)) {\n 52             \/\/  \u751f\u6210Token\n 53             String token = JWTUtil.generateToken(userId, secretKey);\n 54 \n 55             \/\/  \u751f\u6210\u5237\u65b0Token\n 56             String refreshToken = UUID.randomUUID().toString().replace(\"-\", \"\");\n 57 \n 58             \/\/  \u653e\u5165\u7f13\u5b58\n 59             HashOperations&lt;String, String, String> hashOperations = stringRedisTemplate.opsForHash();\n 60 \/\/            hashOperations.put(refreshToken, \"token\", token);\n 61 \/\/            hashOperations.put(refreshToken, \"user\", username);\n 62 \/\/            stringRedisTemplate.expire(refreshToken, JWTUtil.TOKEN_EXPIRE_TIME, TimeUnit.MILLISECONDS);\n 63 \n 64             \/**\n 65              * \u5982\u679c\u53ef\u4ee5\u5141\u8bb8\u7528\u6237\u9000\u51fa\u540etoken\u5982\u679c\u5728\u6709\u6548\u671f\u5185\u4ecd\u7136\u53ef\u4ee5\u4f7f\u7528\u7684\u8bdd\uff0c\u90a3\u4e48\u5c31\u4e0d\u9700\u8981\u5b58Redis\n 66              * \u56e0\u4e3a\uff0ctoken\u8981\u8ddf\u7528\u6237\u505a\u5173\u8054\u7684\u8bdd\uff0c\u5c31\u5fc5\u987b\u5f97\u6bcf\u6b21\u90fd\u5e26\u4e00\u4e2a\u7528\u6237\u6807\u8bc6\uff0c\n 67              * \u90a3\u4e48\u6821\u9a8ctoken\u5b9e\u9645\u4e0a\u5c31\u53d8\u6210\u4e86\u6821\u9a8ctoken\u548c\u7528\u6237\u6807\u8bc6\u7684\u5173\u8054\u5173\u7cfb\u662f\u5426\u6b63\u786e\uff0c\u4e14token\u662f\u5426\u6709\u6548\n 68              *\/\n 69 \n 70 \/\/            String key = MD5Encoder.encode(userId.getBytes());\n 71 \n 72             String key = userId;\n 73             hashOperations.put(key, \"token\", token);\n 74             hashOperations.put(key, \"refreshToken\", refreshToken);\n 75             stringRedisTemplate.expire(key, JWTUtil.TOKEN_EXPIRE_TIME, TimeUnit.MILLISECONDS);\n 76 \n 77             LoginResponse loginResponse = new LoginResponse();\n 78             loginResponse.setToken(token);\n 79             loginResponse.setRefreshToken(refreshToken);\n 80             loginResponse.setUsername(userId);\n 81 \n 82             return ResponseResult.success(loginResponse);\n 83         }\n 84 \n 85         return ResponseResult.error(ResponseCodeEnum.LOGIN_ERROR.getCode(), ResponseCodeEnum.LOGIN_ERROR.getMessage());\n 86     }\n 87 \n 88     \/**\n 89      * \u9000\u51fa\n 90      *\/\n 91     @GetMapping(\"\/logout\")\n 92     public ResponseResult logout(@RequestParam(\"userId\") String userId) {\n 93         HashOperations&lt;String, String, String> hashOperations = stringRedisTemplate.opsForHash();\n 94         String key = userId;\n 95         hashOperations.delete(key);\n 96         return ResponseResult.success();\n 97     }\n 98 \n 99     \/**\n100      * \u5237\u65b0Token\n101      *\/\n102     @PostMapping(\"\/refreshToken\")\n103     public ResponseResult refreshToken(@RequestBody @Validated RefreshRequest request, BindingResult bindingResult) {\n104         String userId = request.getUserId();\n105         String refreshToken = request.getRefreshToken();\n106         HashOperations&lt;String, String, String> hashOperations = stringRedisTemplate.opsForHash();\n107         String key = userId;\n108         String originalRefreshToken = hashOperations.get(key, \"refreshToken\");\n109         if (StringUtils.isBlank(originalRefreshToken) || !originalRefreshToken.equals(refreshToken)) {\n110             return ResponseResult.error(ResponseCodeEnum.REFRESH_TOKEN_INVALID.getCode(), ResponseCodeEnum.REFRESH_TOKEN_INVALID.getMessage());\n111         }\n112 \n113         \/\/  \u751f\u6210\u65b0token\n114         String newToken = JWTUtil.generateToken(userId, secretKey);\n115         hashOperations.put(key, \"token\", newToken);\n116         stringRedisTemplate.expire(userId, JWTUtil.TOKEN_EXPIRE_TIME, TimeUnit.MILLISECONDS);\n117 \n118         return ResponseResult.success(newToken);\n119     }\n120 }<\/pre>\n\n\n\n<p><strong>HelloController.java<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">1 package com.cjs.example.controller;\n 2 \n 3 import org.springframework.web.bind.annotation.GetMapping;\n 4 import org.springframework.web.bind.annotation.RequestHeader;\n 5 import org.springframework.web.bind.annotation.RequestMapping;\n 6 import org.springframework.web.bind.annotation.RestController;\n 7 \n 8 \/**\n 9  * @author ChengJianSheng\n10  * @date 2020-03-08\n11  *\/\n12 @RestController\n13 @RequestMapping(\"\/hello\")\n14 public class HelloController {\n15 \n16     @GetMapping(\"\/sayHello\")\n17     public String sayHello(String name) {\n18         return \"Hello, \" + name;\n19     }\n20 \n21     @GetMapping(\"\/sayHi\")\n22     public String sayHi(@RequestHeader(\"userId\") String userId) {\n23         return userId;\n24     }\n25 \n26 }<\/pre>\n\n\n\n<p><strong>application.yml<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">1 server:\n 2   port: 8081\n 3   servlet:\n 4     context-path: \/auth-server\n 5 spring:\n 6   application:\n 7     name: cjs-auth-service\n 8   redis:\n 9     host: 127.0.0.1\n10     password: 123456\n11     port: 6379\n12     lettuce:\n13       pool:\n14         max-active: 10\n15         max-idle: 5\n16         min-idle: 5\n17         max-wait: 5000\n<\/pre>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">2. \u6821\u9a8cToken<\/h4>\n\n\n\n<p>GatewayFilter\u548cGlobalFilter\u90fd\u53ef\u4ee5\uff0c\u8fd9\u91cc\u7528GlobalFilter<\/p>\n\n\n\n<p><strong>pom.xml<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> 1 &lt;?xml version=\"1.0\" encoding=\"UTF-8\"?>\n 2 &lt;project xmlns=\"http:\/\/maven.apache.org\/POM\/4.0.0\" xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"\n 3          xsi:schemaLocation=\"http:\/\/maven.apache.org\/POM\/4.0.0 https:\/\/maven.apache.org\/xsd\/maven-4.0.0.xsd\">\n 4     &lt;modelVersion>4.0.0&lt;\/modelVersion>\n 5     &lt;parent>\n 6         &lt;groupId>org.springframework.boot&lt;\/groupId>\n 7         &lt;artifactId>spring-boot-starter-parent&lt;\/artifactId>\n 8         &lt;version>2.2.5.RELEASE&lt;\/version>\n 9         &lt;relativePath\/> &lt;!-- lookup parent from repository -->\n10     &lt;\/parent>\n11     &lt;groupId>com.cms.example&lt;\/groupId>\n12     &lt;artifactId>cjs-gateway-example&lt;\/artifactId>\n13     &lt;version>0.0.1-SNAPSHOT&lt;\/version>\n14     &lt;name>cjs-gateway-example&lt;\/name>\n15 \n16     &lt;properties>\n17         &lt;java.version>1.8&lt;\/java.version>\n18         &lt;spring-cloud.version>Hoxton.SR1&lt;\/spring-cloud.version>\n19     &lt;\/properties>\n20 \n21     &lt;dependencies>\n22         &lt;dependency>\n23             &lt;groupId>org.springframework.boot&lt;\/groupId>\n24             &lt;artifactId>spring-boot-starter-data-redis-reactive&lt;\/artifactId>\n25         &lt;\/dependency>\n26         &lt;dependency>\n27             &lt;groupId>org.springframework.cloud&lt;\/groupId>\n28             &lt;artifactId>spring-cloud-starter-gateway&lt;\/artifactId>\n29         &lt;\/dependency>\n30         &lt;dependency>\n31             &lt;groupId>com.auth0&lt;\/groupId>\n32             &lt;artifactId>java-jwt&lt;\/artifactId>\n33             &lt;version>3.10.0&lt;\/version>\n34         &lt;\/dependency>\n35         &lt;dependency>\n36             &lt;groupId>com.cjs.example&lt;\/groupId>\n37             &lt;artifactId>cjs-commons-jwt&lt;\/artifactId>\n38             &lt;version>1.0-SNAPSHOT&lt;\/version>\n39         &lt;\/dependency>\n40 \n41 \n42         &lt;dependency>\n43             &lt;groupId>org.projectlombok&lt;\/groupId>\n44             &lt;artifactId>lombok&lt;\/artifactId>\n45             &lt;optional>true&lt;\/optional>\n46         &lt;\/dependency>\n47     &lt;\/dependencies>\n48 \n49     &lt;dependencyManagement>\n50         &lt;dependencies>\n51             &lt;dependency>\n52                 &lt;groupId>org.springframework.cloud&lt;\/groupId>\n53                 &lt;artifactId>spring-cloud-dependencies&lt;\/artifactId>\n54                 &lt;version>${spring-cloud.version}&lt;\/version>\n55                 &lt;type>pom&lt;\/type>\n56                 &lt;scope>import&lt;\/scope>\n57             &lt;\/dependency>\n58         &lt;\/dependencies>\n59     &lt;\/dependencyManagement>\n60 \n61     &lt;build>\n62         &lt;plugins>\n63             &lt;plugin>\n64                 &lt;groupId>org.springframework.boot&lt;\/groupId>\n65                 &lt;artifactId>spring-boot-maven-plugin&lt;\/artifactId>\n66             &lt;\/plugin>\n67         &lt;\/plugins>\n68     &lt;\/build>\n69 \n70 &lt;\/project>\n\n<\/pre>\n\n\n\n<p><strong>AuthorizeFilter.java<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">1 package com.cms.example.filter;\n 2 \n 3 import com.alibaba.fastjson.JSON;\n 4 import com.cjs.example.ResponseResult;\n 5 import com.cjs.example.enums.ResponseCodeEnum;\n 6 import com.cjs.example.exception.TokenAuthenticationException;\n 7 import com.cjs.example.utils.JWTUtil;\n 8 import lombok.extern.slf4j.Slf4j;\n 9 import org.apache.commons.lang3.StringUtils;\n10 import org.springframework.beans.factory.annotation.Autowired;\n11 import org.springframework.beans.factory.annotation.Value;\n12 import org.springframework.cloud.gateway.filter.GatewayFilterChain;\n13 import org.springframework.cloud.gateway.filter.GlobalFilter;\n14 import org.springframework.core.Ordered;\n15 import org.springframework.core.io.buffer.DataBuffer;\n16 import org.springframework.data.redis.core.StringRedisTemplate;\n17 import org.springframework.http.HttpStatus;\n18 import org.springframework.http.server.reactive.ServerHttpRequest;\n19 import org.springframework.http.server.reactive.ServerHttpResponse;\n20 import org.springframework.stereotype.Component;\n21 import org.springframework.web.server.ServerWebExchange;\n22 import reactor.core.publisher.Flux;\n23 import reactor.core.publisher.Mono;\n24 \n25 \/**\n26  * @author ChengJianSheng\n27  * @date 2020-03-08\n28  *\/\n29 @Slf4j\n30 @Component\n31 public class AuthorizeFilter implements GlobalFilter, Ordered {\n32 \n33     @Value(\"${secretKey:123456}\")\n34     private String secretKey;\n35 \n36 \/\/    @Autowired\n37 \/\/    private StringRedisTemplate stringRedisTemplate;\n38 \n39     @Override\n40     public Mono&lt;Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {\n41         ServerHttpRequest serverHttpRequest = exchange.getRequest();\n42         ServerHttpResponse serverHttpResponse = exchange.getResponse();\n43         String uri = serverHttpRequest.getURI().getPath();\n44 \n45         \/\/  \u68c0\u67e5\u767d\u540d\u5355\uff08\u914d\u7f6e\uff09\n46         if (uri.indexOf(\"\/auth-server\/login\") >= 0) {\n47             return chain.filter(exchange);\n48         }\n49 \n50         String token = serverHttpRequest.getHeaders().getFirst(\"token\");\n51         if (StringUtils.isBlank(token)) {\n52             serverHttpResponse.setStatusCode(HttpStatus.UNAUTHORIZED);\n53             return getVoidMono(serverHttpResponse, ResponseCodeEnum.TOKEN_MISSION);\n54         }\n55 \n56         \/\/todo \u68c0\u67e5Redis\u4e2d\u662f\u5426\u6709\u6b64Token\n57 \n58         try {\n59             JWTUtil.verifyToken(token, secretKey);\n60         } catch (TokenAuthenticationException ex) {\n61             return getVoidMono(serverHttpResponse, ResponseCodeEnum.TOKEN_INVALID);\n62         } catch (Exception ex) {\n63             return getVoidMono(serverHttpResponse, ResponseCodeEnum.UNKNOWN_ERROR);\n64         }\n65 \n66         String userId = JWTUtil.getUserInfo(token);\n67 \n68         ServerHttpRequest mutableReq = serverHttpRequest.mutate().header(\"userId\", userId).build();\n69         ServerWebExchange mutableExchange = exchange.mutate().request(mutableReq).build();\n70 \n71         return chain.filter(mutableExchange);\n72     }\n73 \n74     private Mono&lt;Void> getVoidMono(ServerHttpResponse serverHttpResponse, ResponseCodeEnum responseCodeEnum) {\n75         serverHttpResponse.getHeaders().add(\"Content-Type\", \"application\/json;charset=UTF-8\");\n76         ResponseResult responseResult = ResponseResult.error(responseCodeEnum.getCode(), responseCodeEnum.getMessage());\n77         DataBuffer dataBuffer = serverHttpResponse.bufferFactory().wrap(JSON.toJSONString(responseResult).getBytes());\n78         return serverHttpResponse.writeWith(Flux.just(dataBuffer));\n79     }\n80 \n81     @Override\n82     public int getOrder() {\n83         return -100;\n84     }\n85 }<\/pre>\n\n\n\n<p><strong>application.yml<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> spring:\n 2   cloud:\n 3     gateway:\n 4       routes:\n 5         - id: path_route\n 6           uri: http:\/\/localhost:8081\/auth-server\/\n 7           filters:\n 8             - MyLog=true\n 9           predicates:\n10             - Path=\/auth-server\/** <\/pre>\n\n\n\n<p>\u8fd9\u91cc\u6211\u8fd8\u81ea\u5b9a\u4e49\u4e86\u4e00\u4e2a\u65e5\u5fd7\u6536\u96c6\u8fc7\u6ee4\u5668<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">1 package com.cms.example.filter;\n 2 \n 3 import org.apache.commons.logging.Log;\n 4 import org.apache.commons.logging.LogFactory;\n 5 import org.springframework.cloud.gateway.filter.GatewayFilter;\n 6 import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;\n 7 import org.springframework.http.server.reactive.ServerHttpRequest;\n 8 import org.springframework.stereotype.Component;\n 9 import reactor.core.publisher.Mono;\n10 \n11 import java.util.Arrays;\n12 import java.util.List;\n13 \n14 \/**\n15  * @author ChengJianSheng\n16  * @date 2020-03-08\n17  *\/\n18 @Component\n19 public class MyLogGatewayFilterFactory extends AbstractGatewayFilterFactory&lt;MyLogGatewayFilterFactory.Config> {\n20 \n21     private static final Log log = LogFactory.getLog(MyLogGatewayFilterFactory.class);\n22     private static final String MY_LOG_START_TIME = MyLogGatewayFilterFactory.class.getName() + \".\" + \"startTime\";\n23 \n24     public MyLogGatewayFilterFactory() {\n25         super(Config.class);\n26     }\n27 \n28     @Override\n29     public List&lt;String> shortcutFieldOrder() {\n30         return Arrays.asList(\"enabled\");\n31     }\n32 \n33     @Override\n34     public GatewayFilter apply(Config config) {\n35         return (exchange, chain) -> {\n36             if (!config.isEnabled()) {\n37                 return chain.filter(exchange);\n38             }\n39             exchange.getAttributes().put(MY_LOG_START_TIME, System.currentTimeMillis());\n40             return chain.filter(exchange).then(Mono.fromRunnable(() -> {\n41                 Long startTime = exchange.getAttribute(MY_LOG_START_TIME);\n42                 if (null != startTime) {\n43                     ServerHttpRequest serverHttpRequest = exchange.getRequest();\n44                     StringBuilder sb = new StringBuilder();\n45                     sb.append(serverHttpRequest.getURI().getRawPath());\n46                     sb.append(\" : \");\n47                     sb.append(serverHttpRequest.getQueryParams());\n48                     sb.append(\" : \");\n49                     sb.append(System.currentTimeMillis() - startTime);\n50                     sb.append(\"ms\");\n51                     log.info(sb.toString());\n52                 }\n53             }));\n54         };\n55     }\n56 \n57     public static class Config {\n58         \/**\n59          * \u662f\u5426\u5f00\u542f\n60          *\/\n61         private boolean enabled;\n62 \n63         public Config() {\n64         }\n65 \n66         public boolean isEnabled() {\n67             return enabled;\n68         }\n69 \n70         public void setEnabled(boolean enabled) {\n71             this.enabled = enabled;\n72         }\n73     }\n74 } <\/pre>\n\n\n\n<p>\u7528Postman\u8bbf\u95ee\u5c31\u80fd\u770b\u5230\u6548\u679c<\/p>\n\n\n\n<p>http:\/\/localhost:8080\/auth-server\/hello\/sayHi<br>http:\/\/localhost:8080\/auth-server\/hello\/sayHello?name=aaa<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-41-1024x354.png\" alt=\"\" class=\"wp-image-5259\" width=\"628\" height=\"217\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-41-1024x354.png 1024w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-41-300x104.png 300w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-41-768x266.png 768w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-41-1536x531.png 1536w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-41-830x287.png 830w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-41-230x80.png 230w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-41-350x121.png 350w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-41-480x166.png 480w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-41.png 1584w\" sizes=\"(max-width: 628px) 100vw, 628px\" \/><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-42-1024x660.png\" alt=\"\" class=\"wp-image-5260\" width=\"610\" height=\"393\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-42-1024x660.png 1024w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-42-300x193.png 300w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-42-768x495.png 768w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-42-830x535.png 830w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-42-230x148.png 230w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-42-350x226.png 350w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-42-480x310.png 480w, https:\/\/92it.top\/wp-content\/uploads\/2022\/03\/\u56fe\u7247-42.png 1250w\" sizes=\"(max-width: 610px) 100vw, 610px\" \/><\/figure><\/div>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>3. Spring Cloud Gateway<\/strong><\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">1 @SpringBootApplication\n 2 public class DemogatewayApplication {\n 3     @Bean\n 4     public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {\n 5         return builder.routes()\n 6             .route(\"path_route\", r -> r.path(\"\/get\")\n 7                 .uri(\"http:\/\/httpbin.org\"))\n 8             .route(\"host_route\", r -> r.host(\"*.myhost.org\")\n 9                 .uri(\"http:\/\/httpbin.org\"))\n10             .route(\"rewrite_route\", r -> r.host(\"*.rewrite.org\")\n11                 .filters(f -> f.rewritePath(\"\/foo\/(?&lt;segment>.*)\", \"\/${segment}\"))\n12                 .uri(\"http:\/\/httpbin.org\"))\n13             .route(\"hystrix_route\", r -> r.host(\"*.hystrix.org\")\n14                 .filters(f -> f.hystrix(c -> c.setName(\"slowcmd\")))\n15                 .uri(\"http:\/\/httpbin.org\"))\n16             .route(\"hystrix_fallback_route\", r -> r.host(\"*.hystrixfallback.org\")\n17                 .filters(f -> f.hystrix(c -> c.setName(\"slowcmd\").setFallbackUri(\"forward:\/hystrixfallback\")))\n18                 .uri(\"http:\/\/httpbin.org\"))\n19             .route(\"limit_route\", r -> r\n20                 .host(\"*.limited.org\").and().path(\"\/anything\/**\")\n21                 .filters(f -> f.requestRateLimiter(c -> c.setRateLimiter(redisRateLimiter())))\n22                 .uri(\"http:\/\/httpbin.org\"))\n23             .build();\n24     }\n25 }<\/pre>\n\n\n\n<h5 class=\"wp-block-heading\"><strong>3.1. GatewayFilter Factories<\/strong><\/h5>\n\n\n\n<p>\u8def\u7531\u8fc7\u6ee4\u5668\u5141\u8bb8\u4ee5\u67d0\u79cd\u65b9\u5f0f\u4fee\u6539\u8f93\u5165\u7684HTTP\u8bf7\u6c42\u6216\u8f93\u51fa\u7684HTTP\u54cd\u5e94\u3002\u8def\u7531\u8fc7\u6ee4\u5668\u9002\u7528\u4e8e\u7279\u5b9a\u8def\u7531\u3002Spring Cloud Gateway\u5305\u62ec\u8bb8\u591a\u5185\u7f6e\u7684GatewayFilter\u5de5\u5382\u3002<\/p>\n\n\n\n<p><strong>3.1.1.&nbsp; AddRequestHeader GatewayFilter Factory&nbsp;<\/strong><\/p>\n\n\n\n<p>AddRequestHeader GatewayFilter \u91c7\u7528name\u548cvalue\u53c2\u6570\u3002&nbsp;<\/p>\n\n\n\n<p>\u4f8b\u5982\uff1a\u4e0b\u9762\u7684\u4f8b\u5b50\uff0c\u5bf9\u4e8e\u6240\u6709\u5339\u914d\u7684\u8bf7\u6c42\uff0c\u5c06\u5728\u4e0b\u6e38\u8bf7\u6c42\u5934\u4e2d\u6dfb\u52a0 X-Request-red\uff1ablue<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> spring:\n2   cloud:\n3     gateway:\n4       routes:\n5       - id: add_request_header_route\n6         uri: https:\/\/example.org\n7         filters:\n8         - AddRequestHeader=X-Request-red, blue <\/pre>\n\n\n\n<p>\u521a\u624d\u8bf4\u4e86\uff0cAddRequestHeader\u91c7\u7528name\u548cvalue\u4f5c\u4e3a\u53c2\u6570\u3002\u800cURI\u4e2d\u7684\u53d8\u91cf\u53ef\u4ee5\u7528\u5728value\u4e2d\uff0c\u4f8b\u5982\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">1 spring:\n 2   cloud:\n 3     gateway:\n 4       routes:\n 5       - id: add_request_header_route\n 6         uri: https:\/\/example.org\n 7         predicates:\n 8         - Path=\/red\/{segment}\n 9         filters:\n10         - AddRequestHeader=X-Request-Red, Blue-{segment}<\/pre>\n\n\n\n<p><strong>3.1.2.&nbsp; AddRequestParameter GatewayFilter Factory&nbsp;<\/strong><\/p>\n\n\n\n<p>AddRequestParameter GatewayFilter \u4e5f\u662f\u91c7\u7528name\u548cvalue\u53c2\u6570<\/p>\n\n\n\n<p>\u4f8b\u5982\uff1a\u4e0b\u9762\u7684\u4f8b\u5b50\uff0c\u5bf9\u4e8e\u6240\u6709\u5339\u914d\u7684\u8bf7\u6c42\uff0c\u5c06\u4f1a\u5728\u4e0b\u6e38\u8bf7\u6c42\u7684\u67e5\u8be2\u5b57\u7b26\u4e32\u4e2d\u6dfb\u52a0 red=blue<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">1 spring:\n2   cloud:\n3     gateway:\n4       routes:\n5       - id: add_request_parameter_route\n6         uri: https:\/\/example.org\n7         filters:\n8         - AddRequestParameter=red, blue<\/pre>\n\n\n\n<p>\u540c\u6837\uff0cAddRequestParameter\u4e5f\u652f\u6301\u5728value\u4e2d\u5f15\u7528URI\u4e2d\u7684\u53d8\u91cf\uff0c\u4f8b\u5982\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> 1 spring:\n 2   cloud:\n 3     gateway:\n 4       routes:\n 5       - id: add_request_parameter_route\n 6         uri: https:\/\/example.org\n 7         predicates:\n 8         - Host: {segment}.myhost.org\n 9         filters:\n10         - AddRequestParameter=foo, bar-{segment}\n\n<\/pre>\n\n\n\n<p><strong>3.1.3.&nbsp; AddResponseHeader GatewayFilter Factory&nbsp;<\/strong><\/p>\n\n\n\n<p>AddResponseHeader GatewayFilter \u4f9d\u7136\u91c7\u7528name\u548cvalue\u53c2\u6570\u3002\u4e0d\u5728\u8d58\u8ff0\uff0c\u5982\u4e0b\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">1 spring:\n2   cloud:\n3     gateway:\n4       routes:\n5       - id: add_response_header_route\n6         uri: https:\/\/example.org\n7         filters:\n8         - AddResponseHeader=X-Response-Red, Blue\n\n<\/pre>\n\n\n\n<p><strong>3.1.4.&nbsp; DedupeResponseHeader GatewayFilter Factory&nbsp;<\/strong><\/p>\n\n\n\n<p>DedupeResponseHeader GatewayFilter \u91c7\u7528\u4e00\u4e2aname\u53c2\u6570\u548c\u4e00\u4e2a\u53ef\u9009\u7684strategy\u53c2\u6570\u3002name\u53ef\u4ee5\u5305\u542b\u4ee5\u7a7a\u683c\u5206\u9694\u7684header\u540d\u79f0\u5217\u8868\u3002\u4f8b\u5982\uff1a\u4e0b\u9762\u7684\u4f8b\u5b50\uff0c\u5982\u679c\u5728\u7f51\u5173CORS\u903b\u8f91\u548c\u4e0b\u6e38\u903b\u8f91\u90fd\u5c06\u5b83\u4eec\u6dfb\u52a0\u7684\u60c5\u51b5\u4e0b\uff0c\u8fd9\u5c06\u5220\u9664Access-Control-Allow-Credentials\u548cAccess-Control-Allow-Origin\u54cd\u5e94\u5934\u4e2d\u7684\u91cd\u590d\u503c\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">1 spring:\n2   cloud:\n3     gateway:\n4       routes:\n5       - id: dedupe_response_header_route\n6         uri: https:\/\/example.org\n7         filters:\n8         - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin<\/pre>\n\n\n\n<p><strong>3.1.5.&nbsp;&nbsp;PrefixPath GatewayFilter Factory<\/strong><\/p>\n\n\n\n<p>PrefixPath GatewayFilter \u53ea\u6709\u4e00\u4e2aprefix\u53c2\u6570\u3002\u4e0b\u9762\u7684\u4f8b\u5b50\uff0c\u5bf9\u4e8e\u6240\u6709\u5339\u914d\u7684\u8bf7\u6c42\uff0c\u5c06\u4f1a\u5728\u8bf7\u6c42url\u4e0a\u52a0\u4e0a\u524d\u7f00\/mypath\uff0c\u56e0\u6b64\u8bf7\u6c42\/hello\u5728\u88ab\u8f6c\u53d1\u540e\u7684url\u53d8\u6210\/mypath\/hello<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">1 spring:\n2   cloud:\n3     gateway:\n4       routes:\n5       - id: prefixpath_route\n6         uri: https:\/\/example.org\n7         filters:\n8         - PrefixPath=\/mypath<\/pre>\n\n\n\n<p><strong>3.1.6.&nbsp;&nbsp;RequestRateLimiter GatewayFilter Factory<\/strong><\/p>\n\n\n\n<p>RequestRateLimiter GatewayFilter \u7528\u4e00\u4e2aRateLimiter\u5b9e\u73b0\u6765\u51b3\u5b9a\u5f53\u524d\u8bf7\u6c42\u662f\u5426\u88ab\u5141\u8bb8\u5904\u7406\u3002\u5982\u679c\u4e0d\u88ab\u5141\u8bb8\uff0c\u9ed8\u8ba4\u5c06\u8fd4\u56de\u4e00\u4e2aHTTP 429\u72b6\u6001\uff0c\u8868\u793a\u592a\u591a\u7684\u8bf7\u6c42\u3002&nbsp;<\/p>\n\n\n\n<p>\u8fd9\u4e2a\u8fc7\u6ee4\u5668\u91c7\u7528\u4e00\u4e2a\u53ef\u9009\u7684keyResolver\u53c2\u6570\u3002keyResolver\u662f\u5b9e\u73b0\u4e86KeyResolver\u63a5\u53e3\u7684\u4e00\u4e2abean\u3002\u5728\u914d\u7f6e\u4e2d\uff0c\u901a\u8fc7SpEL\u8868\u8fbe\u5f0f\u5f15\u7528\u5b83\u3002\u4f8b\u5982\uff0c#{@myKeyResolver}\u662f\u4e00\u4e2aSpEL\u8868\u8fbe\u5f0f\uff0c\u5b83\u662f\u5bf9\u540d\u5b57\u53ebmyKeyResolver\u7684bean\u7684\u5f15\u7528\u3002KeyResolver\u9ed8\u8ba4\u7684\u5b9e\u73b0\u662fPrincipalNameKeyResolver\u3002<\/p>\n\n\n\n<p>\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5982\u679cKeyResolver\u6ca1\u6709\u627e\u5230\u4e00\u4e2akey\uff0c\u90a3\u4e48\u8bf7\u6c42\u5c06\u4f1a\u88ab\u62d2\u7edd\u3002\u4f60\u53ef\u4ee5\u8c03\u6574\u8fd9\u79cd\u884c\u4e3a\uff0c\u901a\u8fc7\u8bbe\u7f6espring.cloud.gateway.filter.request-rate-limiter.deny-empty-key (true or false) \u548c spring.cloud.gateway.filter.request-rate-limiter.empty-key-status-code\u5c5e\u6027\u3002<\/p>\n\n\n\n<p>Redis\u57fa\u4e8e Token Bucket Algorithm \uff08\u4ee4\u724c\u6876\u7b97\u6cd5\uff09\u5b9e\u73b0\u4e86\u4e00\u4e2aRequestRateLimiter<\/p>\n\n\n\n<p>redis-rate-limiter.replenishRate \u5c5e\u6027\u6307\u5b9a\u4e00\u4e2a\u7528\u6237\u6bcf\u79d2\u5141\u8bb8\u591a\u5c11\u4e2a\u8bf7\u6c42\uff0c\u800c\u6ca1\u6709\u4efb\u4f55\u4e22\u5f03\u7684\u8bf7\u6c42\u3002\u8fd9\u662f\u4ee4\u724c\u6876\u88ab\u586b\u5145\u7684\u901f\u7387\u3002<\/p>\n\n\n\n<p>redis-rate-limiter.burstCapacity \u5c5e\u6027\u6307\u5b9a\u7528\u6237\u5728\u4e00\u79d2\u949f\u5185\u6267\u884c\u7684\u6700\u5927\u8bf7\u6c42\u6570\u3002\u8fd9\u662f\u4ee4\u724c\u6876\u53ef\u4ee5\u5bb9\u7eb3\u7684\u4ee4\u724c\u6570\u3002\u5c06\u6b64\u503c\u8bbe\u7f6e\u4e3a\u96f6\u5c06\u963b\u6b62\u6240\u6709\u8bf7\u6c42\u3002<\/p>\n\n\n\n<p>redis-rate-limiter.requestedTokens \u5c5e\u6027\u6307\u5b9a\u4e00\u4e2a\u8bf7\u6c42\u8981\u82b1\u8d39\u591a\u5c11\u4e2a\u4ee4\u724c\u3002\u8fd9\u662f\u6bcf\u4e2a\u8bf7\u6c42\u4ece\u5b58\u50a8\u6876\u4e2d\u83b7\u53d6\u7684\u4ee4\u724c\u6570\uff0c\u9ed8\u8ba4\u4e3a1\u3002<\/p>\n\n\n\n<p>\u901a\u8fc7\u5c06replenishRate\u548cburstCapacity\u8bbe\u7f6e\u6210\u76f8\u540c\u7684\u503c\u53ef\u4ee5\u5b9e\u73b0\u7a33\u5b9a\u7684\u901f\u7387\u3002\u901a\u8fc7\u5c06burstCapacity\u8bbe\u7f6e\u4e3a\u9ad8\u4e8ereplenishRate\uff0c\u53ef\u4ee5\u5141\u8bb8\u4e34\u65f6\u7a81\u53d1\u3002 \u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u901f\u7387\u9650\u5236\u5668\u9700\u8981\u5728\u4e24\u6b21\u7a81\u53d1\u4e4b\u95f4\u4fdd\u7559\u4e00\u6bb5\u65f6\u95f4\uff08\u6839\u636ereplenishRate\uff09\uff0c\u56e0\u4e3a\u4e24\u4e2a\u8fde\u7eed\u7684\u7a81\u53d1\u5c06\u5bfc\u81f4\u8bf7\u6c42\u4e22\u5f03\uff08HTTP 429-\u592a\u591a\u8bf7\u6c42\uff09\u3002&nbsp;<\/p>\n\n\n\n<p>\u901a\u8fc7\u5c06replenishRate\u8bbe\u7f6e\u4e3a\u6240\u9700\u7684\u8bf7\u6c42\u6570\uff0c\u5c06requestTokens\u8bbe\u7f6e\u4e3a\u4ee5\u79d2\u4e3a\u5355\u4f4d\u7684\u65f6\u95f4\u8de8\u5ea6\u5e76\u5c06burstCapacity\u8bbe\u7f6e\u4e3areplenishRate\u548crequestedToken\u7684\u4e58\u79ef\u3002\u53ef\u4ee5\u8fbe\u52301\u4e2a\u8bf7\u6c42\u7684\u901f\u7387\u9650\u5236\u3002 \u4f8b\u5982\uff1a\u8bbe\u7f6ereplenishRate = 1\uff0crequestedTokens = 60\u548cburstCapacity = 60\u5c06\u5bfc\u81f4\u9650\u5236\u4e3a\u6bcf\u5206\u949f1\u4e2a\u8bf7\u6c42\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">1 spring:\n 2   cloud:\n 3     gateway:\n 4       routes:\n 5       - id: requestratelimiter_route\n 6         uri: https:\/\/example.org\n 7         filters:\n 8         - name: RequestRateLimiter\n 9           args:\n10             redis-rate-limiter.replenishRate: 10\n11             redis-rate-limiter.burstCapacity: 20\n12             redis-rate-limiter.requestedTokens: 1 <\/pre>\n\n\n\n<p>KeyResolver<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">1 @Bean\n2 KeyResolver userKeyResolver() {\n3     return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst(\"user\"));\n4 }\n\n<\/pre>\n\n\n\n<p>\u4e0a\u9762\u7684\u4f8b\u5b50\uff0c\u5b9a\u4e49\u4e86\u6bcf\u4e2a\u7528\u6237\u6bcf\u79d2\u8fd0\u884c10\u4e2a\u8bf7\u6c42\uff0c\u4ee4\u724c\u6876\u7684\u5bb9\u91cf\u662f20\uff0c\u90a3\u4e48\uff0c\u4e0b\u4e00\u79d2\u5c06\u53ea\u5269\u4e0b10\u4e2a\u4ee4\u724c\u53ef\u7528\u3002KeyResolver\u5b9e\u73b0\u4ec5\u4ec5\u53ea\u662f\u7b80\u5355\u53d6\u8bf7\u6c42\u53c2\u6570\u4e2d\u7684user\uff0c\u5f53\u7136\u5728\u751f\u4ea7\u73af\u5883\u4e2d\u4e0d\u63a8\u8350\u8fd9\u4e48\u505a\u3002<\/p>\n\n\n\n<p>\u8bf4\u767d\u4e86\uff0cKeyResolver\u5c31\u662f\u51b3\u5b9a\u54ea\u4e9b\u8bf7\u6c42\u5c5e\u4e8e\u540c\u4e00\u4e2a\u7528\u6237\u7684\u3002\u6bd4\u5982\uff0cheader\u4e2duserId\u76f8\u540c\u7684\u5c31\u8ba4\u4e3a\u662f\u540c\u4e00\u4e2a\u7528\u6237\u7684\u8bf7\u6c42\u3002<\/p>\n\n\n\n<p>\u5f53\u7136\uff0c\u4f60\u4e5f\u53ef\u4ee5\u81ea\u5df1\u5b9e\u73b0\u4e00\u4e2aRateLimiter\uff0c\u5728\u914d\u7f6e\u7684\u65f6\u5019\u7528SpEL\u8868\u8fbe\u5f0f#{@myRateLimiter}\u53bb\u5f15\u7528\u5b83\u3002\u4f8b\u5982\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> 1 spring:\n 2   cloud:\n 3     gateway:\n 4       routes:\n 5       - id: requestratelimiter_route\n 6         uri: https:\/\/example.org\n 7         filters:\n 8         - name: RequestRateLimiter\n 9           args:\n10             rate-limiter: \"#{@myRateLimiter}\"\n11             key-resolver: \"#{@userKeyResolver}\"\n\n<\/pre>\n\n\n\n<p>\u8865\u5145\uff1a\uff08Token Bucket\uff09\u4ee4\u724c\u6876<\/p>\n\n\n\n<p><a href=\"https:\/\/en.wikipedia.org\/wiki\/Token_bucket\">https:\/\/en.wikipedia.org\/wiki\/Token_bucket<\/a><\/p>\n\n\n\n<p>\u4ee4\u724c\u6876\u662f\u5728\u5206\u7ec4\u4ea4\u6362\u8ba1\u7b97\u673a\u7f51\u7edc\u548c\u7535\u4fe1\u7f51\u7edc\u4e2d\u4f7f\u7528\u7684\u7b97\u6cd5\u3002\u5b83\u53ef\u4ee5\u7528\u6765\u68c0\u67e5\u6570\u636e\u5305\u5f62\u5f0f\u7684\u6570\u636e\u4f20\u8f93\u662f\u5426\u7b26\u5408\u5b9a\u4e49\u7684\u5e26\u5bbd\u548c\u7a81\u53d1\u6027\u9650\u5236\uff08\u5bf9\u6d41\u91cf\u4e0d\u5747\u5300\u6027\u6216\u53d8\u5316\u7684\u5ea6\u91cf\uff09\u3002<\/p>\n\n\n\n<p>\u4ee4\u724c\u6876\u7b97\u6cd5\u5c31\u597d\u6bd4\u662f\u4e00\u4e2a\u7684\u56fa\u5b9a\u5bb9\u91cf\u6876\uff0c\u901a\u5e38\u4ee5\u56fa\u5b9a\u901f\u7387\u5411\u5176\u4e2d\u6dfb\u52a0\u4ee4\u724c\u3002\u4e00\u4e2a\u4ee4\u724c\u901a\u5e38\u4ee3\u8868\u4e00\u4e2a\u5b57\u8282\u3002\u5f53\u8981\u68c0\u67e5\u6570\u636e\u5305\u662f\u5426\u7b26\u5408\u5b9a\u4e49\u7684\u9650\u5236\u65f6\uff0c\u5c06\u68c0\u67e5\u4ee4\u724c\u6876\u4ee5\u67e5\u770b\u5176\u5f53\u65f6\u662f\u5426\u5305\u542b\u8db3\u591f\u7684\u4ee4\u724c\u3002\u5982\u679c\u6709\u8db3\u591f\u6570\u91cf\u7684\u4ee4\u724c\uff0c\u5e76\u5047\u8bbe\u4ee4\u724c\u4ee5\u5b57\u8282\u4e3a\u5355\u4f4d\uff0c\u90a3\u4e48\uff0c\u4e0e\u6570\u636e\u5305\u5b57\u8282\u6570\u91cf\u7b49\u6548\u6570\u91cf\u7684\u4ee4\u724c\u5c06\u88ab\u5220\u9664\uff0c\u5e76\u4e14\u8be5\u6570\u636e\u5305\u53ef\u4ee5\u901a\u8fc7\u7ee7\u7eed\u4f20\u8f93\u3002\u5982\u679c\u4ee4\u724c\u6876\u4e2d\u7684\u4ee4\u724c\u6570\u91cf\u4e0d\u591f\uff0c\u5219\u6570\u636e\u5305\u4e0d\u7b26\u5408\u8981\u6c42\uff0c\u5e76\u4e14\u4ee4\u724c\u6876\u7684\u4ee4\u724c\u6570\u91cf\u4e0d\u4f1a\u53d8\u5316\u3002\u4e0d\u5408\u683c\u7684\u6570\u636e\u5305\u53ef\u4ee5\u6709\u591a\u79cd\u5904\u7406\u65b9\u5f0f\uff1a<\/p>\n\n\n\n<ul><li>\u5b83\u4eec\u53ef\u80fd\u4f1a\u88ab\u4e22\u5f03<\/li><li>\u5f53\u6876\u4e2d\u79ef\u7d2f\u4e86\u8db3\u591f\u7684\u4ee4\u724c\u65f6\uff0c\u53ef\u4ee5\u5c06\u5b83\u4eec\u52a0\u5165\u961f\u5217\u8fdb\u884c\u540e\u7eed\u4f20\u8f93<\/li><li>\u5b83\u4eec\u53ef\u4ee5\u88ab\u4f20\u8f93\uff0c\u4f46\u88ab\u6807\u8bb0\u4e3a\u4e0d\u7b26\u5408\uff0c\u5982\u679c\u7f51\u7edc\u8d1f\u8f7d\u8fc7\u9ad8\uff0c\u53ef\u80fd\u968f\u540e\u88ab\u4e22\u5f03<\/li><\/ul>\n\n\n\n<p>\uff08PS\uff1a\u8fd9\u53e5\u8bdd\u7684\u610f\u601d\u662f\u8bf4\uff0c\u60f3\u8c61\u6709\u4e00\u4e2a\u6876\uff0c\u4ee5\u56fa\u5b9a\u901f\u7387\u5411\u6876\u4e2d\u6dfb\u52a0\u4ee4\u724c\u3002\u5047\u8bbe\u4e00\u4e2a\u4ee4\u724c\u7b49\u6548\u4e8e\u4e00\u4e2a\u5b57\u8282\uff0c\u5f53\u4e00\u4e2a\u6570\u636e\u5305\u5230\u8fbe\u65f6\uff0c\u5047\u8bbe\u8fd9\u4e2a\u6570\u636e\u5305\u7684\u5927\u5c0f\u662fn\u5b57\u8282\uff0c\u5982\u679c\u6876\u4e2d\u6709\u8db3\u591f\u591a\u7684\u4ee4\u724c\uff0c\u5373\u6876\u4e2d\u4ee4\u724c\u7684\u6570\u91cf\u5927\u4e8en\uff0c\u5219\u8be5\u6570\u636e\u53ef\u4ee5\u901a\u8fc7\uff0c\u5e76\u4e14\u6876\u4e2d\u8981\u5220\u9664n\u4e2a\u4ee4\u724c\u3002\u5982\u679c\u6876\u4e2d\u4ee4\u724c\u6570\u4e0d\u591f\uff0c\u5219\u6839\u636e\u60c5\u51b5\u8be5\u6570\u636e\u5305\u53ef\u80fd\u76f4\u63a5\u88ab\u4e22\u5f03\uff0c\u4e5f\u53ef\u80fd\u4e00\u76f4\u7b49\u5f85\u76f4\u5230\u4ee4\u724c\u8db3\u591f\uff0c\u4e5f\u53ef\u80fd\u7ee7\u7eed\u4f20\u8f93\uff0c\u4f46\u88ab\u6807\u8bb0\u4e3a\u4e0d\u5408\u683c\u3002\u8fd8\u662f\u4e0d\u591f\u901a\u4fd7\uff0c\u8fd9\u6837\uff0c\u5982\u679c\u628a\u4ee4\u724c\u6876\u60f3\u8c61\u6210\u4e00\u4e2a\u6c34\u6876\u7684\u8bdd\uff0c\u4ee4\u724c\u60f3\u8c61\u6210\u6c34\u6ef4\u7684\u8bdd\uff0c\u90a3\u4e48\u8fd9\u4e2a\u8fc7\u7a0b\u5c31\u53d8\u6210\u4e86\u4ee5\u6052\u5b9a\u901f\u7387\u5411\u6c34\u6876\u4e2d\u6ef4\u6c34\uff0c\u5f53\u6709\u4eba\u60f3\u6253\u4e00\u7897\u6c34\u65f6\uff0c\u5982\u679c\u8fd9\u4e2a\u4eba\u7684\u7897\u5f88\u5c0f\uff0c\u53ea\u80fd\u88c530\u6ef4\u6c34\uff0c\u800c\u6c34\u6876\u4e2d\u6c34\u6ef4\u6570\u91cf\u8d85\u8fc730\uff0c\u90a3\u4e48\u8fd9\u4e2a\u4eba\u5c31\u53ef\u4ee5\u6253\u4e00\u7897\u6c34\uff0c\u7136\u540e\u5c31\u8d70\u4e86\uff0c\u76f8\u5e94\u7684\uff0c\u6c34\u6876\u4e2d\u7684\u6c34\u5728\u8fd9\u4e2a\u4eba\u6253\u5b8c\u4ee5\u540e\u81ea\u7136\u5c31\u5c11\u4e8630\u6ef4\u3002\u8fc7\u4e86\u4e00\u4f1a\u513f\uff0c\u53c8\u6709\u4e00\u4e2a\u4eba\u6765\u6253\u6c34\uff0c\u4ed6\u62ff\u7684\u7897\u6bd4\u8f83\u5927\uff0c\u4e00\u6b21\u80fd\u88c5100\u6ef4\u6c34\uff0c\u8fd9\u65f6\u5019\u6876\u91cc\u7684\u6c34\u4e0d\u591f\uff0c\u8fd9\u4e2a\u65f6\u5019\u4ed6\u53ef\u80fd\u5c31\u8d70\u4e86\uff0c\u6216\u8005\u5728\u8fd9\u513f\u7b49\u7740\uff0c\u7b49\u5230\u6876\u4e2d\u79ef\u7d2f\u4e86100\u6ef4\u7684\u65f6\u5019\u518d\u6253\u3002\u54c8\u54c8\u54c8\uff0c\u5c31\u662f\u9171\u7d2b\uff0c\u4e0d\u77e5\u9053\u5927\u5bb6\u89c1\u8fc7\u6c34\u8f66\u6ca1\u6709\u2026\u2026\uff09<\/p>\n\n\n\n<p>\u4ee4\u724c\u6876\u7b97\u6cd5\u53ef\u4ee5\u7b80\u5355\u5730\u8fd9\u6837\u7406\u89e3\uff1a<\/p>\n\n\n\n<ul><li>\u6bcf 1\/r \u79d2\u6709\u4e00\u4e2a\u4ee4\u724c\u88ab\u6dfb\u52a0\u5230\u4ee4\u724c\u6876<\/li><li>\u4ee4\u724c\u6876\u6700\u591a\u53ef\u4ee5\u5bb9\u7eb3 b \u4e2a\u4ee4\u724c\u3002\u5f53\u4e00\u4e2a\u4ee4\u724c\u5230\u8fbe\u65f6\uff0c\u4ee4\u724c\u6876\u5df2\u7ecf\u6ee1\u4e86\uff0c\u90a3\u4e48\u5b83\u5c06\u4f1a\u88ab\u4e22\u5f03\u3002<\/li><li>\u5f53\u4e00\u4e2a n \u5b57\u8282\u5927\u5c0f\u7684\u6570\u636e\u5305\u5230\u8fbe\u65f6\uff1a<ul><li>\u5982\u679c\u4ee4\u724c\u6876\u4e2d\u81f3\u5c11\u6709n\u4e2a\u4ee4\u724c\uff0c\u5219\u4ece\u4ee4\u724c\u6876\u4e2d\u5220\u9664n\u4e2a\u4ee4\u724c\uff0c\u5e76\u5c06\u6570\u636e\u5305\u53d1\u9001\u5230\u7f51\u7edc\u3002<\/li><li>\u5982\u679c\u53ef\u7528\u7684\u4ee4\u724c\u5c11\u4e8en\u4e2a\uff0c\u5219\u4e0d\u4f1a\u4ece\u4ee4\u724c\u6876\u4e2d\u5220\u9664\u4efb\u4f55\u4ee4\u724c\uff0c\u5e76\u4e14\u5c06\u6570\u636e\u5305\u89c6\u4e3a\u4e0d\u5408\u683c\u3002\u3000<\/li><\/ul><\/li><\/ul>\n\n\n\n<p><strong>3.1.7.&nbsp;RedirectTo GatewayFilter Factory&nbsp;<\/strong><\/p>\n\n\n\n<p>RedirectTo GatewayFilter \u6709\u4e24\u4e2a\u53c2\u6570\uff1astatus \u548c url\u3002status\u5e94\u8be5\u662f300\u7cfb\u5217\u7684\u3002\u4e0d\u89e3\u91ca\uff0c\u770b\u793a\u4f8b\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">1 spring:\n2   cloud:\n3     gateway:\n4       routes:\n5       - id: prefixpath_route\n6         uri: https:\/\/example.org\n7         filters:\n8         - RedirectTo=302, https:\/\/acme.org\n\n<\/pre>\n\n\n\n<p><strong>3.1.8.&nbsp; RemoveRequestHeader GatewayFilter Factory&nbsp;<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">1 spring:\n2   cloud:\n3     gateway:\n4       routes:\n5       - id: removerequestheader_route\n6         uri: https:\/\/example.org\n7         filters:\n8         - RemoveRequestHeader=X-Request-Foo\n\n<\/pre>\n\n\n\n<p><strong>3.1.9.&nbsp; RewritePath GatewayFilter Factory&nbsp;<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">1 spring:\n 2   cloud:\n 3     gateway:\n 4       routes:\n 5       - id: rewritepath_route\n 6         uri: https:\/\/example.org\n 7         predicates:\n 8         - Path=\/foo\/**\n 9         filters:\n10         - RewritePath=\/red(?&lt;segment>\/?.*), $\\{segment}<\/pre>\n\n\n\n<p><strong>3.1.10.&nbsp; Default Filters&nbsp;<\/strong><\/p>\n\n\n\n<p>\u4e3a\u4e86\u6dfb\u52a0\u4e00\u4e2a\u8fc7\u6ee4\u5668\uff0c\u5e76\u5c06\u5176\u5e94\u7528\u5230\u6240\u6709\u8def\u7531\u4e0a\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528spring.cloud.gateway.default-filters\uff0c\u8fd9\u4e2a\u5c5e\u6027\u503c\u662f\u4e00\u4e2a\u8fc7\u6ee4\u5668\u5217\u8868<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">1 spring:\n2   cloud:\n3     gateway:\n4       default-filters:\n5       - AddResponseHeader=X-Response-Default-Red, Default-Blue\n6       - PrefixPath=\/httpbin\n\n<\/pre>\n\n\n\n<h5 class=\"wp-block-heading\"><strong>3.2. Global Filters<\/strong><\/h5>\n\n\n\n<p>GlobalFilter\u5e94\u7528\u4e8e\u6240\u6709\u8def\u7531<\/p>\n\n\n\n<p><strong>3.2.1.&nbsp; GlobalFilter\u4e0eGatewayFilter\u7ec4\u5408\u7684\u987a\u5e8f&nbsp;<\/strong><\/p>\n\n\n\n<p>\u5f53\u4e00\u4e2a\u8bf7\u6c42\u8bf7\u6c42\u4e0e\u5339\u914d\u67d0\u4e2a\u8def\u7531\u65f6\uff0c\u8fc7\u6ee4Web\u5904\u7406\u7a0b\u5e8f\u4f1a\u5c06GlobalFilter\u7684\u6240\u6709\u5b9e\u4f8b\u548cGatewayFilter\u7684\u6240\u6709\u7279\u5b9a\u4e8e\u8def\u7531\u7684\u5b9e\u4f8b\u6dfb\u52a0\u5230\u8fc7\u6ee4\u5668\u94fe\u4e2d\u3002\u8be5\u7ec4\u5408\u7684\u8fc7\u6ee4\u5668\u94fe\u7531org.springframework.core.Ordered\u63a5\u53e3\u6392\u5e8f\uff0c\u53ef\u4ee5\u901a\u8fc7\u5b9e\u73b0getOrder()\u65b9\u6cd5\u8fdb\u884c\u8bbe\u7f6e\u3002<\/p>\n\n\n\n<p>\u7531\u4e8eSpring Cloud Gateway\u533a\u5206\u8fc7\u6ee4\u5668\u903b\u8f91\u6267\u884c\u7684\u201cpre\u201d\u548c\u201cpost\u201d\u9636\u6bb5\uff0c\u56e0\u6b64\uff0c\u4f18\u5148\u7ea7\u6700\u9ad8\u7684\u8fc7\u6ee4\u5668\u5728\u201cpre\u201d\u9636\u6bb5\u662f\u7b2c\u4e00\u4e2a\uff0c\u5728\u201cpost\u201d\u9636\u6bb5\u662f\u6700\u540e\u4e00\u4e2a\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">1 @Bean\n 2 public GlobalFilter customFilter() {\n 3     return new CustomGlobalFilter();\n 4 }\n 5 \n 6 public class CustomGlobalFilter implements GlobalFilter, Ordered {\n 7 \n 8     @Override\n 9     public Mono&lt;Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {\n10         log.info(\"custom global filter\");\n11         return chain.filter(exchange);\n12     }\n13 \n14     @Override\n15     public int getOrder() {\n16         return -1;\n17     }\n18 }<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">    \u8865\u5145\uff1a\uff08Token Bucket\uff09\u4ee4\u724c\u6876\n\n    https:\/\/en.wikipedia.org\/wiki\/Token_bucket\n\n    \u4ee4\u724c\u6876\u662f\u5728\u5206\u7ec4\u4ea4\u6362\u8ba1\u7b97\u673a\u7f51\u7edc\u548c\u7535\u4fe1\u7f51\u7edc\u4e2d\u4f7f\u7528\u7684\u7b97\u6cd5\u3002\u5b83\u53ef\u4ee5\u7528\u6765\u68c0\u67e5\u6570\u636e\u5305\u5f62\u5f0f\u7684\u6570\u636e\u4f20\u8f93\u662f\u5426\u7b26\u5408\u5b9a\u4e49\u7684\u5e26\u5bbd\u548c\u7a81\u53d1\u6027\u9650\u5236\uff08\u5bf9\u6d41\u91cf\u4e0d\u5747\u5300\u6027\u6216\u53d8\u5316\u7684\u5ea6\u91cf\uff09\u3002\n\n    \u4ee4\u724c\u6876\u7b97\u6cd5\u5c31\u597d\u6bd4\u662f\u4e00\u4e2a\u7684\u56fa\u5b9a\u5bb9\u91cf\u6876\uff0c\u901a\u5e38\u4ee5\u56fa\u5b9a\u901f\u7387\u5411\u5176\u4e2d\u6dfb\u52a0\u4ee4\u724c\u3002\u4e00\u4e2a\u4ee4\u724c\u901a\u5e38\u4ee3\u8868\u4e00\u4e2a\u5b57\u8282\u3002\u5f53\u8981\u68c0\u67e5\u6570\u636e\u5305\u662f\u5426\u7b26\u5408\u5b9a\u4e49\u7684\u9650\u5236\u65f6\uff0c\u5c06\u68c0\u67e5\u4ee4\u724c\u6876\u4ee5\u67e5\u770b\u5176\u5f53\u65f6\u662f\u5426\u5305\u542b\u8db3\u591f\u7684\u4ee4\u724c\u3002\u5982\u679c\u6709\u8db3\u591f\u6570\u91cf\u7684\u4ee4\u724c\uff0c\u5e76\u5047\u8bbe\u4ee4\u724c\u4ee5\u5b57\u8282\u4e3a\u5355\u4f4d\uff0c\u90a3\u4e48\uff0c\u4e0e\u6570\u636e\u5305\u5b57\u8282\u6570\u91cf\u7b49\u6548\u6570\u91cf\u7684\u4ee4\u724c\u5c06\u88ab\u5220\u9664\uff0c\u5e76\u4e14\u8be5\u6570\u636e\u5305\u53ef\u4ee5\u901a\u8fc7\u7ee7\u7eed\u4f20\u8f93\u3002\u5982\u679c\u4ee4\u724c\u6876\u4e2d\u7684\u4ee4\u724c\u6570\u91cf\u4e0d\u591f\uff0c\u5219\u6570\u636e\u5305\u4e0d\u7b26\u5408\u8981\u6c42\uff0c\u5e76\u4e14\u4ee4\u724c\u6876\u7684\u4ee4\u724c\u6570\u91cf\u4e0d\u4f1a\u53d8\u5316\u3002\u4e0d\u5408\u683c\u7684\u6570\u636e\u5305\u53ef\u4ee5\u6709\u591a\u79cd\u5904\u7406\u65b9\u5f0f\uff1a\n\n        \u5b83\u4eec\u53ef\u80fd\u4f1a\u88ab\u4e22\u5f03\n        \u5f53\u6876\u4e2d\u79ef\u7d2f\u4e86\u8db3\u591f\u7684\u4ee4\u724c\u65f6\uff0c\u53ef\u4ee5\u5c06\u5b83\u4eec\u52a0\u5165\u961f\u5217\u8fdb\u884c\u540e\u7eed\u4f20\u8f93\n        \u5b83\u4eec\u53ef\u4ee5\u88ab\u4f20\u8f93\uff0c\u4f46\u88ab\u6807\u8bb0\u4e3a\u4e0d\u7b26\u5408\uff0c\u5982\u679c\u7f51\u7edc\u8d1f\u8f7d\u8fc7\u9ad8\uff0c\u53ef\u80fd\u968f\u540e\u88ab\u4e22\u5f03\n\n    \uff08PS\uff1a\u8fd9\u53e5\u8bdd\u7684\u610f\u601d\u662f\u8bf4\uff0c\u60f3\u8c61\u6709\u4e00\u4e2a\u6876\uff0c\u4ee5\u56fa\u5b9a\u901f\u7387\u5411\u6876\u4e2d\u6dfb\u52a0\u4ee4\u724c\u3002\u5047\u8bbe\u4e00\u4e2a\u4ee4\u724c\u7b49\u6548\u4e8e\u4e00\u4e2a\u5b57\u8282\uff0c\u5f53\u4e00\u4e2a\u6570\u636e\u5305\u5230\u8fbe\u65f6\uff0c\u5047\u8bbe\u8fd9\u4e2a\u6570\u636e\u5305\u7684\u5927\u5c0f\u662fn\u5b57\u8282\uff0c\u5982\u679c\u6876\u4e2d\u6709\u8db3\u591f\u591a\u7684\u4ee4\u724c\uff0c\u5373\u6876\u4e2d\u4ee4\u724c\u7684\u6570\u91cf\u5927\u4e8en\uff0c\u5219\u8be5\u6570\u636e\u53ef\u4ee5\u901a\u8fc7\uff0c\u5e76\u4e14\u6876\u4e2d\u8981\u5220\u9664n\u4e2a\u4ee4\u724c\u3002\u5982\u679c\u6876\u4e2d\u4ee4\u724c\u6570\u4e0d\u591f\uff0c\u5219\u6839\u636e\u60c5\u51b5\u8be5\u6570\u636e\u5305\u53ef\u80fd\u76f4\u63a5\u88ab\u4e22\u5f03\uff0c\u4e5f\u53ef\u80fd\u4e00\u76f4\u7b49\u5f85\u76f4\u5230\u4ee4\u724c\u8db3\u591f\uff0c\u4e5f\u53ef\u80fd\u7ee7\u7eed\u4f20\u8f93\uff0c\u4f46\u88ab\u6807\u8bb0\u4e3a\u4e0d\u5408\u683c\u3002\u8fd8\u662f\u4e0d\u591f\u901a\u4fd7\uff0c\u8fd9\u6837\uff0c\u5982\u679c\u628a\u4ee4\u724c\u6876\u60f3\u8c61\u6210\u4e00\u4e2a\u6c34\u6876\u7684\u8bdd\uff0c\u4ee4\u724c\u60f3\u8c61\u6210\u6c34\u6ef4\u7684\u8bdd\uff0c\u90a3\u4e48\u8fd9\u4e2a\u8fc7\u7a0b\u5c31\u53d8\u6210\u4e86\u4ee5\u6052\u5b9a\u901f\u7387\u5411\u6c34\u6876\u4e2d\u6ef4\u6c34\uff0c\u5f53\u6709\u4eba\u60f3\u6253\u4e00\u7897\u6c34\u65f6\uff0c\u5982\u679c\u8fd9\u4e2a\u4eba\u7684\u7897\u5f88\u5c0f\uff0c\u53ea\u80fd\u88c530\u6ef4\u6c34\uff0c\u800c\u6c34\u6876\u4e2d\u6c34\u6ef4\u6570\u91cf\u8d85\u8fc730\uff0c\u90a3\u4e48\u8fd9\u4e2a\u4eba\u5c31\u53ef\u4ee5\u6253\u4e00\u7897\u6c34\uff0c\u7136\u540e\u5c31\u8d70\u4e86\uff0c\u76f8\u5e94\u7684\uff0c\u6c34\u6876\u4e2d\u7684\u6c34\u5728\u8fd9\u4e2a\u4eba\u6253\u5b8c\u4ee5\u540e\u81ea\u7136\u5c31\u5c11\u4e8630\u6ef4\u3002\u8fc7\u4e86\u4e00\u4f1a\u513f\uff0c\u53c8\u6709\u4e00\u4e2a\u4eba\u6765\u6253\u6c34\uff0c\u4ed6\u62ff\u7684\u7897\u6bd4\u8f83\u5927\uff0c\u4e00\u6b21\u80fd\u88c5100\u6ef4\u6c34\uff0c\u8fd9\u65f6\u5019\u6876\u91cc\u7684\u6c34\u4e0d\u591f\uff0c\u8fd9\u4e2a\u65f6\u5019\u4ed6\u53ef\u80fd\u5c31\u8d70\u4e86\uff0c\u6216\u8005\u5728\u8fd9\u513f\u7b49\u7740\uff0c\u7b49\u5230\u6876\u4e2d\u79ef\u7d2f\u4e86100\u6ef4\u7684\u65f6\u5019\u518d\u6253\u3002\u54c8\u54c8\u54c8\uff0c\u5c31\u662f\u9171\u7d2b\uff0c\u4e0d\u77e5\u9053\u5927\u5bb6\u89c1\u8fc7\u6c34\u8f66\u6ca1\u6709\u2026\u2026\uff09\n\n    \u4ee4\u724c\u6876\u7b97\u6cd5\u53ef\u4ee5\u7b80\u5355\u5730\u8fd9\u6837\u7406\u89e3\uff1a\n\n        \u6bcf 1\/r \u79d2\u6709\u4e00\u4e2a\u4ee4\u724c\u88ab\u6dfb\u52a0\u5230\u4ee4\u724c\u6876\n        \u4ee4\u724c\u6876\u6700\u591a\u53ef\u4ee5\u5bb9\u7eb3 b \u4e2a\u4ee4\u724c\u3002\u5f53\u4e00\u4e2a\u4ee4\u724c\u5230\u8fbe\u65f6\uff0c\u4ee4\u724c\u6876\u5df2\u7ecf\u6ee1\u4e86\uff0c\u90a3\u4e48\u5b83\u5c06\u4f1a\u88ab\u4e22\u5f03\u3002\n        \u5f53\u4e00\u4e2a n \u5b57\u8282\u5927\u5c0f\u7684\u6570\u636e\u5305\u5230\u8fbe\u65f6\uff1a\n            \u5982\u679c\u4ee4\u724c\u6876\u4e2d\u81f3\u5c11\u6709n\u4e2a\u4ee4\u724c\uff0c\u5219\u4ece\u4ee4\u724c\u6876\u4e2d\u5220\u9664n\u4e2a\u4ee4\u724c\uff0c\u5e76\u5c06\u6570\u636e\u5305\u53d1\u9001\u5230\u7f51\u7edc\u3002\n            \u5982\u679c\u53ef\u7528\u7684\u4ee4\u724c\u5c11\u4e8en\u4e2a\uff0c\u5219\u4e0d\u4f1a\u4ece\u4ee4\u724c\u6876\u4e2d\u5220\u9664\u4efb\u4f55\u4ee4\u724c\uff0c\u5e76\u4e14\u5c06\u6570\u636e\u5305\u89c6\u4e3a\u4e0d\u5408\u683c\u3002\u3000\n\n<\/pre>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">4.\u81ea\u5df1\u5199\u7684\u4e00\u4e2aDemo<\/h4>\n\n\n\n<ul><li><strong>login-api\u4e2d\u5bf9\u7528\u6237\u540d\u548c\u5bc6\u7801\u8fdb\u884c\u6821\u9a8c\uff0c\u901a\u8fc7\u540e\uff0c\u53d1\u884ctoken.<\/strong><\/li><\/ul>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">    public String loginVerify(@RequestBody User user, HttpServletResponse response) {\n        \/\/ \u8fd9\u91cc\u628aPassword\u8fdb\u884c\u53cd\u7f16\u8bd1\n        String inputPassword = DigestUtils.md5DigestAsHex(user.getPassword().getBytes());\n        \/\/ \u68c0\u7d22\u6570\u636e\u5e93\u9a8c\u8bc1Password\n        List&lt;User> resultList = loginApiService.loginVerify(user.getUserId(), inputPassword);\n        \/\/ \u9a8c\u8bc1\u901a\u8fc7\u540e\uff0c\u901a\u8fc7JWT\u751f\u6210Token\n        String token = jwtUtil.generateToken(user.getUserId());\n        response.addHeader(\"token\", token);\n        return token;\n        \n    }<\/pre>\n\n\n\n<ul><li><strong>JWTUtil<\/strong><\/li><\/ul>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@Service\npublic class JWTUtil {\n\n    public static final long TOKEN_EXPIRE_TIME = 7200 * 1000;\n    private static final String ISSUER = \"test\";\n\n    @Value(\"${secretTokenKey}\")\n    private String secretTokenKey;\n\n \n    public String generateToken(String userId) {\n        Algorithm algorithm = Algorithm.HMAC256(secretTokenKey);\n        Date now = new Date();\n        Date expireTime = new Date(now.getTime() + TOKEN_EXPIRE_TIME);\n\n        String token = JWT.create().withIssuer(ISSUER).withIssuedAt(now).withExpiresAt(expireTime)\n                .withClaim(\"userId\", userId).sign(algorithm);\n        return token;\n    }\n\n    public boolean verifyToken(String token) {\n\n        try {\n            Algorithm algorithm = Algorithm.HMAC256(secretTokenKey);\n            JWTVerifier jwtVerifier = JWT.require(algorithm).withIssuer(ISSUER).build();\n            jwtVerifier.verify(token);\n\n        } catch (JWTDecodeException jwtDecodeException) {\n            return false;\n        } catch (SignatureVerificationException signatureVerificationException) {\n            return false;\n        } catch (TokenExpiredException tokenExpiredException) {\n            return false;\n        } catch (Exception ex) {\n            return false;\n        }\n        return true;\n    }\n\n    public String getUserInfo(String token) {\n        DecodedJWT decodedJWT = JWT.decode(token);\n        String userId = decodedJWT.getClaim(\"userId\").asString();\n        return userId;\n    }\n\n}<\/pre>\n\n\n\n<ul><li><strong>GateWay\u7f51\u5173\u7684\u4ee3\u7801<\/strong><\/li><\/ul>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.cloud.gateway.filter.GatewayFilterChain;\nimport org.springframework.cloud.gateway.filter.GlobalFilter;\nimport org.springframework.core.Ordered;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.web.server.ServerWebExchange;\n\nimport reactor.core.publisher.Mono;\n\npublic class AuthFilter implements GlobalFilter, Ordered {\n\n    @Value(\"${serviceApiKey}\")\n    private String serviceApiKey;\n\n    @Value(\"${secretTokenKey}\")\n    private String secretTokenKey;\n\n    @Autowired\n    private JWTUtil jwtUtil;\n\n    @Override\n    public Mono&lt;Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {\n\n        String inApikey = exchange.getRequest().getHeaders().getFirst(\"apikey\");\n        String inApikeyUrl = exchange.getRequest().getQueryParams().getFirst(\"apikey\");\n        String token = exchange.getRequest().getHeaders().getFirst(\"token\");\n        String isCheckToken = exchange.getRequest().getHeaders().getFirst(\"isCheckToken\");\n        String uri = exchange.getRequest().getURI().getPath();\n\n        \/\/ \u9a8c\u8bc1APIKEY\u7684\u60c5\u62a5\n        if (!(serviceApiKey.equals(inApikey) || serviceApiKey.equals(inApikeyUrl))) {\n            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);\n            return exchange.getResponse().setComplete();\n        } else {\n            \/\/ login\u7684\u65f6\u5019\uff0c\u653e\u884c\u3002\n            if (uri.indexOf(\"\/login-api\/loginVerify\") >= 0) {\n                return chain.filter(exchange.mutate().request(exchange.getRequest()).build());\n            } else {\n                \/\/ Token\u9a8c\u8bc1\u5fc5\u8981\u7684\u65f6\u5019\n                if (\"Y\".equals(isCheckToken)) {\n                    if (StringUtils.isBlank(token)) {\n                        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);\n                        return exchange.getResponse().setComplete();\n                    }\n\n                    \/\/ \u901a\u8fc7JWT\u9a8c\u8bc1Token\n                    if (!jwtUtil.verifyToken(token)) {\n                        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);\n                        return exchange.getResponse().setComplete();\n                    } else {\n                        \/\/ \u5982\u679cToken\u9a8c\u8bc1\u901a\u8fc7\uff0c\u53d6\u5f97Token\u91cc\u9762\u7684\u5185\u5bb9\uff0c\u91cd\u65b0\u4f5c\u6210\u4e00\u4e2a\u65b0\u7684Token\u5237\u65b0\n                        String userId = jwtUtil.getUserInfo(token);\n                        String refreshToken = jwtUtil.generateToken(userId);\n                        exchange.getResponse().getHeaders().add(\"token\", token);\n                        exchange.getResponse().getHeaders().add(\"refreshToken\", refreshToken);\n                        return chain.filter(exchange.mutate().request(exchange.getRequest()).build());\n                    }\n                }\n                return chain.filter(exchange.mutate().request(exchange.getRequest()).build());\n            }\n        }\n    }\n\n    @Override\n    public int getOrder() {\n        return 1;\n    }\n}<\/pre>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">5. Docs<\/h4>\n\n\n\n<p><a href=\"https:\/\/cloud.spring.io\/spring-cloud-static\/spring-cloud-gateway\/2.2.2.RELEASE\/reference\/html\/#gatewayfilter-factories\">https:\/\/cloud.spring.io\/spring-cloud-static\/spring-cloud-gateway\/2.2.2.RELEASE\/reference\/html\/#gatewayfilter-factories<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/cloud.spring.io\/spring-cloud-static\/spring-cloud-gateway\/2.2.2.RELEASE\/reference\/html\/#gateway-request-predicates-factories\">https:\/\/cloud.spring.io\/spring-cloud-static\/spring-cloud-gateway\/2.2.2.RELEASE\/reference\/html\/#gateway-request-predicates-factories<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/mp.weixin.qq.com\/\">https:\/\/mp.weixin.qq.com\/<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/en.wikipedia.org\/wiki\/Token_bucket\">https:\/\/en.wikipedia.org\/wiki\/Token_bucket<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u5728\u6211\u770b\u6765\uff0c\u5728\u67d0\u4e9b\u573a\u666f\u4e0b\uff0c\u7f51\u5173\u5c31\u50cf\u662f\u4e00\u4e2a\u516c\u5171\u65b9\u6cd5\uff0c\u628a\u9879\u76ee\u4e2d\u7684\u90fd\u8981\u7528\u5230\u7684\u4e00\u4e9b\u529f\u80fd\u63d0\u51fa\u6765\uff0c\u62bd\u8c61\u6210\u4e00\u4e2a\u670d\u52a1\u3002\u6bd4\u5982\uff0c\u6211\u4eec [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26,27],"tags":[],"_links":{"self":[{"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/posts\/5244"}],"collection":[{"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/92it.top\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=5244"}],"version-history":[{"count":14,"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/posts\/5244\/revisions"}],"predecessor-version":[{"id":5268,"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/posts\/5244\/revisions\/5268"}],"wp:attachment":[{"href":"https:\/\/92it.top\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=5244"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/92it.top\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=5244"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/92it.top\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=5244"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}