You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by ni...@apache.org on 2018/07/19 22:48:00 UTC

[incubator-servicecomb-website] branch master updated (40ee158 -> e525e2e)

This is an automated email from the ASF dual-hosted git repository.

ningjiang pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-servicecomb-website.git.


    from 40ee158  Updated the home page
     new 2d5206b  easy-build-microservice-system-part-IV blog
     new 9f20aca  fix style mistake
     new e525e2e  fix pr comments

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 ...07-10-easy-build-microservice-system-part-IV.md | 198 +++++++++++++++++++++
 assets/images/scaffold/AuthSuccess.png             | Bin 0 -> 100204 bytes
 assets/images/scaffold/EdgeAuth.png                | Bin 0 -> 31684 bytes
 assets/images/scaffold/ErrorAuthHeader.png         | Bin 0 -> 106784 bytes
 assets/images/scaffold/FilterChain.png             | Bin 0 -> 22932 bytes
 assets/images/scaffold/LoginFirst.png              | Bin 0 -> 108269 bytes
 assets/images/scaffold/NoAuthHeader.png            | Bin 0 -> 104790 bytes
 7 files changed, 198 insertions(+)
 create mode 100644 _posts/cn/2018-07-10-easy-build-microservice-system-part-IV.md
 create mode 100644 assets/images/scaffold/AuthSuccess.png
 create mode 100644 assets/images/scaffold/EdgeAuth.png
 create mode 100644 assets/images/scaffold/ErrorAuthHeader.png
 create mode 100644 assets/images/scaffold/FilterChain.png
 create mode 100644 assets/images/scaffold/LoginFirst.png
 create mode 100644 assets/images/scaffold/NoAuthHeader.png


[incubator-servicecomb-website] 01/03: easy-build-microservice-system-part-IV blog

Posted by ni...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ningjiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-servicecomb-website.git

commit 2d5206bfa446e409f7fef9299d18b61811e82adc
Author: zhengyangyong <ya...@huawei.com>
AuthorDate: Mon Jul 9 14:05:43 2018 +0800

    easy-build-microservice-system-part-IV blog
    
    Signed-off-by: zhengyangyong <ya...@huawei.com>
---
 ...07-10-easy-build-microservice-system-part-IV.md | 272 +++++++++++++++++++++
 assets/images/scaffold/AuthSuccess.png             | Bin 0 -> 100204 bytes
 assets/images/scaffold/EdgeAuth.png                | Bin 0 -> 31684 bytes
 assets/images/scaffold/ErrorAuthHeader.png         | Bin 0 -> 106784 bytes
 assets/images/scaffold/FilterChain.png             | Bin 0 -> 22686 bytes
 assets/images/scaffold/LoginFirst.png              | Bin 0 -> 108269 bytes
 assets/images/scaffold/NoAuthHeader.png            | Bin 0 -> 104790 bytes
 7 files changed, 272 insertions(+)

diff --git a/_posts/cn/2018-07-10-easy-build-microservice-system-part-IV.md b/_posts/cn/2018-07-10-easy-build-microservice-system-part-IV.md
new file mode 100644
index 0000000..5860f57
--- /dev/null
+++ b/_posts/cn/2018-07-10-easy-build-microservice-system-part-IV.md
@@ -0,0 +1,272 @@
+---
+title: "轻松微服务系列:边缘服务支持统一认证"
+lang: cn
+ref: easy-build-microservice-system-part-IV
+permalink: /cn/docs/easy-build-microservice-system-part-IV/
+excerpt: "轻松微服务系列:边缘服务支持统一认证"
+last_modified_at: 2018-07-10T19:00:00+08:00
+author: Yangyong Zheng
+tags: [Edge Service,API Gateway,Authentication]
+redirect_from:
+  - /theme-setup/
+---
+
+## 轻松微服务系列:边缘服务支持统一认证
+在前一篇博文[《轻松微服务系列:开发高性能边缘服务》](http://servicecomb.incubator.apache.org/cn/docs/easy-build-microservice-system-part-III/),我们开发了具备基本路由能力的高性能边缘服务。这篇博文我们将在Edge服务上实施如何扩展支持统一认证。
+
+### 设计思路
+正如前面的博文提到过,统一认证的目的是在Edge入口处进行访问认证,避免需要在所有的微服务中都承载重复的认证机制,因此:
+1. 我们先要将认证功能作为一个独立的Procuder发布出来,使Edge服务能够随时认证Token,我们将其命名为`AuthenticationService`,放在用户服务中;
+2. 将无需认证的访问请求识别出来,包括:
+
+| 功能      | 描述                     |
+| :------- | :--------------------- |
+| login    | 登录验证,通过后为用户生成Token |
+| logon    | 新用户注册                  |
+
+除此之外其他业务请求都需要做Token认证;
+3. Edge服务转发访问请求之前,对需要认证的请求先做统一认证,认证通过之后才转发,为了能够未来更好的扩展这种“转发前处理”的能力,我们设计一个处理链机制——`FilterChain`:
+
+![FilterChain](/assets/images/scaffold/FilterChain.png)
+
+>提示:另外一种方案就是扩展Handler,如果检查失败则使Handler链调用直接返回;但是由于认证过程同样是一个Consumer调用,也会触发Handler 处理,这会使Handler的逻辑和配置复杂化,因此此场景下不推荐。
+
+完整统一认证时序图为:
+
+![EdgeAuth](/assets/images/scaffold/EdgeAuth.png)
+
+### 实现统一认证
+#### 第一步:发布认证服务
+##### 定义AuthenticationService
+```java
+public interface AuthenticationService {
+  String validate(String token);
+}
+```
+##### 实现并发布AuthenticationService
+```java
+@RestSchema(schemaId = "authentication")
+@RequestMapping(path = "/")
+public class AuthenticationServiceImpl implements AuthenticationService {
+
+  private final TokenStore tokenStore;
+
+  @Autowired
+  public AuthenticationServiceImpl(TokenStore tokenStore) {
+    this.tokenStore = tokenStore;
+  }
+
+  @Override
+  @GetMapping(path = "validate")
+  public String validate(String token) {
+    String userName = tokenStore.validate(token);
+    if (userName == null) {
+      throw new InvocationException(BAD_REQUEST, "incorrect token");
+    }
+    return userName;
+  }
+}
+```
+
+#### 第二步:实现转发前处理链FilterChain
+##### 定义处理链接口EdgeFilter
+```java
+public interface EdgeFilter {
+  //Filter的处理顺序,越小越先被处理
+  int getOrder();
+
+  //如果需要中止Filter链执行,抛InvocationException即可
+  void processing(String serviceName, String operationPath, RoutingContext context) throws InvocationException;
+}
+```
+##### 实现统一认证AuthenticationFilter
+```java
+public class AuthenticationFilter implements EdgeFilter {
+
+  private final RestTemplate template = RestTemplateBuilder.create();
+
+  private static final String USER_SERVICE_NAME = "user-service";
+
+  public static final String EDGE_AUTHENTICATION_NAME = "edge-authentication-name";
+
+  private static final Set<String> NOT_REQUIRED_VERIFICATION_USER_SERVICE_METHODS = new HashSet<>(
+      Arrays.asList("/login", "/logon", "/validate"));
+
+  @Override
+  public int getOrder() {
+    return 0;
+  }
+
+  @Override
+  public void processing(String serviceName, String operationPath, RoutingContext context) throws InvocationException {
+    if (isInvocationNeedValidate(serviceName, operationPath)) {
+      String token = context.request().headers().get(AUTHORIZATION);
+      if (StringUtils.isNotEmpty(token)) {
+        String userName = template
+            .getForObject("cse://" + USER_SERVICE_NAME + "/validate?token={token}", String.class, token);
+        if (StringUtils.isNotEmpty(userName)) {
+          //Add header
+          context.request().headers().add(EDGE_AUTHENTICATION_NAME, userName);
+        } else {
+          throw new InvocationException(Status.UNAUTHORIZED, "authentication failed, invalid token");
+        }
+      } else {
+        throw new InvocationException(Status.UNAUTHORIZED, "authentication failed, missing AUTHORIZATION header");
+      }
+    }
+  }
+
+  private boolean isInvocationNeedValidate(String serviceName, String operationPath) {
+    if (USER_SERVICE_NAME.equals(serviceName)) {
+      for (String method : NOT_REQUIRED_VERIFICATION_USER_SERVICE_METHODS) {
+        if (operationPath.startsWith(method)) {
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+}
+```
+
+#### 第三步:在Edge中添加FilterChain调用机制
+##### 在EdgeDispatcher中链式递归的方式顺序调用所有的EdgeFilter
+```java
+  private void onRequest(RoutingContext context) {
+    Map<String, String> pathParams = context.pathParams();
+    //从匹配的param0拿到{ServiceComb微服务Name}
+    final String service = pathParams.get("param0");
+    //从匹配的param1拿到{服务路径&参数}
+    String operationPath = "/" + pathParams.get("param1");
+
+    //还记得我们之前说的做出一点点改进吗?引入一个自定义配置edge.routing-short-path.{简称},映射微服务名;如果简称没有配置,那么就认为直接是微服务的名
+    final String serviceName = DynamicPropertyFactory.getInstance()
+        .getStringProperty("edge.routing-short-path." + service, service).get();
+
+      //创建一个Edge转发
+    EdgeInvocation edgeInvocation = new EdgeInvocation();
+    //允许接受任意版本的微服务实例作为Provider,未来我们会使用此(设置版本)能力实现灰度发布
+    edgeInvocation.setVersionRule(DefinitionConst.VERSION_RULE_ALL);
+    edgeInvocation.init(serviceName, context, path, httpServerFilters);
+
+    //处理Filter链,如果全部通过则转发请求
+    loopExecuteEdgeFilterInChain(0, serviceName, operationPath, context, edgeInvocation);
+  }
+
+  private void loopExecuteEdgeFilterInChain(int index, String serviceName, String operationPath, RoutingContext context,
+      EdgeInvocation edgeInvocation) {
+    if (index < filterChain.size()) {
+      EdgeFilter filter = filterChain.get(index);
+      AtomicReference<InvocationException> exception = new AtomicReference<>();
+      CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
+        try {
+          filter.processing(serviceName, operationPath, context);
+        } catch (InvocationException e) {
+          exception.set(e);
+        }
+      });
+
+      future.whenComplete((result, throwable) -> {
+        if (exception.get() != null) {
+          sendFailed(context, exception.get());
+        } else if (throwable != null) {
+          sendFailed(context, new InvocationException(Status.INTERNAL_SERVER_ERROR, throwable.getMessage()));
+        } else {
+          loopExecuteEdgeFilterInChain(index + 1, serviceName, operationPath, context, edgeInvocation);
+        }
+      });
+    } else {
+      try {
+        edgeInvocation.edgeInvoke();
+      } catch (InvocationException e) {
+        sendFailed(context, e);
+      }
+    }
+  }
+
+  private void sendFailed(RoutingContext context, InvocationException exception) {
+    context.response().setStatusCode(exception.getStatusCode());
+    context.response().headers().add(CONTENT_LENGTH, String.valueOf(exception.getMessage().length()));
+    context.response().write(exception.getMessage());
+    context.response().end();
+  }
+```
+
+>提示:Edge默认工作于全异步模式下,不允许有任何阻塞操作,`AuthenticationFilter`是一个RPC调用,所以`loopExecuteEdgeFilterInChain`中调用EdgeFilter使用的是异步回调模式。
+
+##### 使用SPI方式加载所有的EdgeFilter
+在`resources\META-INF\services`目录中创建`org.apache.servicecomb.scaffold.edge.EdgeFilter`文件:
+```text
+org.apache.servicecomb.scaffold.edge.filter.AuthenticationFilter
+```
+
+之后在EdgeDispatcher增加SPI加载所有的EdgeFilter的逻辑:
+```java
+private final List<EdgeFilter> filterChain;
+
+public EdgeDispatcher() {
+    filterChain = SPIServiceUtils.getSortedService(EdgeFilter.class);
+  }
+```
+
+#### 第四步:在用户微服务中增加修改密码的功能用于验证
+现有的`login`和`logon`都无需认证,因此我们在用户微服务中增加需要认证的修改密码的功能用于验证统一认证。
+##### 在UserService中添加修改密码
+```java
+public interface UserService {
+  ResponseEntity<Boolean> logon(UserDTO user);
+
+  ResponseEntity<Boolean> login(UserDTO user);
+  //需要认证的修改密码功能
+  ResponseEntity<Boolean> changePassword(UserUpdateDTO userUpdate);
+}
+```
+
+##### 在UserServiceImpl中实现修改密码
+```java
+@Override
+@PostMapping(path = "changePassword")
+public ResponseEntity<Boolean> changePassword(@RequestBody UserUpdateDTO userUpdate) {
+  if (validateUserUpdate(userUpdate)) {
+    UserEntity dbUser = repository.findByName(userUpdate.getName());
+    if (dbUser != null) {
+      if (dbUser.getPassword().equals(userUpdate.getOldPassword())) {
+        dbUser.setPassword(userUpdate.getNewPassword());
+        repository.save(dbUser);
+        return new ResponseEntity<>(true, HttpStatus.OK);
+      }
+      throw new InvocationException(BAD_REQUEST, "wrong password");
+    }
+    throw new InvocationException(BAD_REQUEST, "user name not exist");
+  }
+  throw new InvocationException(BAD_REQUEST, "incorrect user");
+}
+```
+
+### 验证实现的统一认证
+#### 用户登录
+使用zhengyangyong登录:
+
+![LoginFirst](/assets/images/scaffold/LoginFirst.png)
+
+拿到的Token值为:eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ6aGVuZ3lhbmd5b25nIiwiZXhwIjoxNTMwNjA4OTczfQ.90teWUNbypPZvds_SD7Kus_y7wLc4b6VzC_aIVg8sLItKxwQ0g4V9BDU665PlqQY5KM-mnk8y0R6ENL1T8YVFg
+
+#### 不带Authorization Header请求changePassword
+
+![NoAuthHeader](/assets/images/scaffold/NoAuthHeader.png)
+
+返回的失败信息是:authentication failed, missing AUTHORIZATION header
+
+#### 使用错误的Token请求changePassword
+
+![ErrorAuthHeader](/assets/images/scaffold/ErrorAuthHeader.png)
+
+返回的失败信息是:authentication failed : InvocationException: code=400;msg=CommonExceptionData [message=incorrect token]
+
+#### 使用正确的Token请求changePassword
+
+![AuthSuccess](/assets/images/scaffold/AuthSuccess.png)
+
+修改密码成功。
+
+**这里可能有疑问,使用zhengyangyong登录后,是可以通过这个Token修改其他用户例如lidagang的密码的,这是因为我们目前构建的validate仅检查Token的有效性,而不做权限检查,基于RBAC的角色权限管理系统将会在未来构建。**
\ No newline at end of file
diff --git a/assets/images/scaffold/AuthSuccess.png b/assets/images/scaffold/AuthSuccess.png
new file mode 100644
index 0000000..bc60deb
Binary files /dev/null and b/assets/images/scaffold/AuthSuccess.png differ
diff --git a/assets/images/scaffold/EdgeAuth.png b/assets/images/scaffold/EdgeAuth.png
new file mode 100644
index 0000000..024a93f
Binary files /dev/null and b/assets/images/scaffold/EdgeAuth.png differ
diff --git a/assets/images/scaffold/ErrorAuthHeader.png b/assets/images/scaffold/ErrorAuthHeader.png
new file mode 100644
index 0000000..3a11818
Binary files /dev/null and b/assets/images/scaffold/ErrorAuthHeader.png differ
diff --git a/assets/images/scaffold/FilterChain.png b/assets/images/scaffold/FilterChain.png
new file mode 100644
index 0000000..717c07e
Binary files /dev/null and b/assets/images/scaffold/FilterChain.png differ
diff --git a/assets/images/scaffold/LoginFirst.png b/assets/images/scaffold/LoginFirst.png
new file mode 100644
index 0000000..ff8427c
Binary files /dev/null and b/assets/images/scaffold/LoginFirst.png differ
diff --git a/assets/images/scaffold/NoAuthHeader.png b/assets/images/scaffold/NoAuthHeader.png
new file mode 100644
index 0000000..9931594
Binary files /dev/null and b/assets/images/scaffold/NoAuthHeader.png differ


[incubator-servicecomb-website] 03/03: fix pr comments

Posted by ni...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ningjiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-servicecomb-website.git

commit e525e2ea27d8d17e75303d6ec1c9bbaa97961325
Author: zhengyangyong <ya...@huawei.com>
AuthorDate: Fri Jul 13 15:14:53 2018 +0800

    fix pr comments
    
    Signed-off-by: zhengyangyong <ya...@huawei.com>
---
 ...07-10-easy-build-microservice-system-part-IV.md | 129 +++++----------------
 assets/images/scaffold/FilterChain.png             | Bin 22686 -> 22932 bytes
 2 files changed, 27 insertions(+), 102 deletions(-)

diff --git a/_posts/cn/2018-07-10-easy-build-microservice-system-part-IV.md b/_posts/cn/2018-07-10-easy-build-microservice-system-part-IV.md
index e79ba84..c1ec64e 100644
--- a/_posts/cn/2018-07-10-easy-build-microservice-system-part-IV.md
+++ b/_posts/cn/2018-07-10-easy-build-microservice-system-part-IV.md
@@ -26,13 +26,11 @@ redirect_from:
 
 除此之外其他业务请求都需要做Token认证;
 
-3. Edge服务转发访问请求之前,对需要认证的请求先做统一认证,认证通过之后才转发,为了能够未来更好的扩展这种“转发前处理”的能力,我们设计一个处理链机制`FilterChain`:
+3. Edge服务转发访问请求之前,对需要认证的请求先做统一认证,认证通过之后才转发,我们使用`HttpServerFilter`扩展这个能力:
 
 ![FilterChain](/assets/images/scaffold/FilterChain.png)
 
->提示:另外一种方案就是扩展Handler,如果检查失败则使Handler链调用直接返回;但是由于认证过程同样是一个Consumer调用,也会触发Handler 处理,这会使Handler的逻辑和配置复杂化,因此此场景下不推荐。
-
-完整统一认证时序图为:
+统一认证流程时序图为:
 
 ![EdgeAuth](/assets/images/scaffold/EdgeAuth.png)
 
@@ -69,20 +67,9 @@ public class AuthenticationServiceImpl implements AuthenticationService {
 }
 ```
 
-#### 第二步:实现转发前处理链FilterChain
-##### 定义处理链接口EdgeFilter
-```java
-public interface EdgeFilter {
-  //Filter的处理顺序,越小越先被处理
-  int getOrder();
-
-  //如果需要中止Filter链执行,抛InvocationException即可
-  void processing(String serviceName, String operationPath, RoutingContext context) throws InvocationException;
-}
-```
-##### 实现统一认证AuthenticationFilter
+#### 第二步:实现统一认证AuthenticationFilter
 ```java
-public class AuthenticationFilter implements EdgeFilter {
+public class AuthenticationFilter implements HttpServerFilter {
 
   private final RestTemplate template = RestTemplateBuilder.create();
 
@@ -91,7 +78,7 @@ public class AuthenticationFilter implements EdgeFilter {
   public static final String EDGE_AUTHENTICATION_NAME = "edge-authentication-name";
 
   private static final Set<String> NOT_REQUIRED_VERIFICATION_USER_SERVICE_METHODS = new HashSet<>(
-      Arrays.asList("/login", "/logon", "/validate"));
+      Arrays.asList("login", "logon", "validate"));
 
   @Override
   public int getOrder() {
@@ -99,22 +86,25 @@ public class AuthenticationFilter implements EdgeFilter {
   }
 
   @Override
-  public void processing(String serviceName, String operationPath, RoutingContext context) throws InvocationException {
-    if (isInvocationNeedValidate(serviceName, operationPath)) {
-      String token = context.request().headers().get(AUTHORIZATION);
+  public Response afterReceiveRequest(Invocation invocation, HttpServletRequestEx httpServletRequestEx) {
+    if (isInvocationNeedValidate(invocation.getMicroserviceName(), invocation.getOperationName())) {
+      String token = httpServletRequestEx.getHeader(AUTHORIZATION);
       if (StringUtils.isNotEmpty(token)) {
         String userName = template
             .getForObject("cse://" + USER_SERVICE_NAME + "/validate?token={token}", String.class, token);
         if (StringUtils.isNotEmpty(userName)) {
           //Add header
-          context.request().headers().add(EDGE_AUTHENTICATION_NAME, userName);
+          invocation.getContext().put(EDGE_AUTHENTICATION_NAME, userName);
         } else {
-          throw new InvocationException(Status.UNAUTHORIZED, "authentication failed, invalid token");
+          return Response
+              .failResp(new InvocationException(Status.UNAUTHORIZED, "authentication failed, invalid token"));
         }
       } else {
-        throw new InvocationException(Status.UNAUTHORIZED, "authentication failed, missing AUTHORIZATION header");
+        return Response.failResp(
+            new InvocationException(Status.UNAUTHORIZED, "authentication failed, missing AUTHORIZATION header"));
       }
     }
+    return null;
   }
 
   private boolean isInvocationNeedValidate(String serviceName, String operationPath) {
@@ -130,87 +120,12 @@ public class AuthenticationFilter implements EdgeFilter {
 }
 ```
 
-#### 第三步:在Edge中添加FilterChain调用机制
-##### 在EdgeDispatcher中链式递归的方式顺序调用所有的EdgeFilter
-```java
-  private void onRequest(RoutingContext context) {
-    Map<String, String> pathParams = context.pathParams();
-    //从匹配的param0拿到{ServiceComb微服务Name}
-    final String service = pathParams.get("param0");
-    //从匹配的param1拿到{服务路径&参数}
-    String operationPath = "/" + pathParams.get("param1");
-
-    //还记得我们之前说的做出一点点改进吗?引入一个自定义配置edge.routing-short-path.{简称},映射微服务名;如果简称没有配置,那么就认为直接是微服务的名
-    final String serviceName = DynamicPropertyFactory.getInstance()
-        .getStringProperty("edge.routing-short-path." + service, service).get();
-
-      //创建一个Edge转发
-    EdgeInvocation edgeInvocation = new EdgeInvocation();
-    //允许接受任意版本的微服务实例作为Provider,未来我们会使用此(设置版本)能力实现灰度发布
-    edgeInvocation.setVersionRule(DefinitionConst.VERSION_RULE_ALL);
-    edgeInvocation.init(serviceName, context, path, httpServerFilters);
-
-    //处理Filter链,如果全部通过则转发请求
-    loopExecuteEdgeFilterInChain(0, serviceName, operationPath, context, edgeInvocation);
-  }
-
-  private void loopExecuteEdgeFilterInChain(int index, String serviceName, String operationPath, RoutingContext context,
-      EdgeInvocation edgeInvocation) {
-    if (index < filterChain.size()) {
-      EdgeFilter filter = filterChain.get(index);
-      AtomicReference<InvocationException> exception = new AtomicReference<>();
-      CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
-        try {
-          filter.processing(serviceName, operationPath, context);
-        } catch (InvocationException e) {
-          exception.set(e);
-        }
-      });
-
-      future.whenComplete((result, throwable) -> {
-        if (exception.get() != null) {
-          sendFailed(context, exception.get());
-        } else if (throwable != null) {
-          sendFailed(context, new InvocationException(Status.INTERNAL_SERVER_ERROR, throwable.getMessage()));
-        } else {
-          loopExecuteEdgeFilterInChain(index + 1, serviceName, operationPath, context, edgeInvocation);
-        }
-      });
-    } else {
-      try {
-        edgeInvocation.edgeInvoke();
-      } catch (InvocationException e) {
-        sendFailed(context, e);
-      }
-    }
-  }
-
-  private void sendFailed(RoutingContext context, InvocationException exception) {
-    context.response().setStatusCode(exception.getStatusCode());
-    context.response().headers().add(CONTENT_LENGTH, String.valueOf(exception.getMessage().length()));
-    context.response().write(exception.getMessage());
-    context.response().end();
-  }
-```
-
->提示:Edge默认工作于全异步模式下,不允许有任何阻塞操作,`AuthenticationFilter`是一个RPC调用,所以`loopExecuteEdgeFilterInChain`中调用EdgeFilter使用的是异步回调模式。
-
-##### 使用SPI方式加载所有的EdgeFilter
-在`resources\META-INF\services`目录中创建`org.apache.servicecomb.scaffold.edge.EdgeFilter`文件:
+别忘了通过SPI机制加载它,在`resources\META-INF\services`目录中创建`org.apache.servicecomb.common.rest.filter.HttpServerFilter`文件:
 ```text
 org.apache.servicecomb.scaffold.edge.filter.AuthenticationFilter
 ```
 
-之后在EdgeDispatcher增加SPI加载所有的EdgeFilter的逻辑:
-```java
-private final List<EdgeFilter> filterChain;
-
-public EdgeDispatcher() {
-    filterChain = SPIServiceUtils.getSortedService(EdgeFilter.class);
-  }
-```
-
-#### 第四步:在用户微服务中增加修改密码的功能用于验证
+#### 第三步:在用户微服务中增加修改密码的功能用于验证
 现有的`login`和`logon`都无需认证,因此我们在用户微服务中增加需要认证的修改密码的功能用于验证统一认证。
 ##### 在UserService中添加修改密码
 ```java
@@ -245,6 +160,12 @@ public ResponseEntity<Boolean> changePassword(@RequestBody UserUpdateDTO userUpd
 ```
 
 ### 验证实现的统一认证
+#### 确认AuthenticationFilter在Edge服务中成功加载
+在Edge服务的启动日志中能够找到:
+```text
+2018-07-13 14:38:48,756 [INFO]   1. org.apache.servicecomb.scaffold.edge.filter.AuthenticationFilter. org.apache.servicecomb.foundation.common.utils.SPIServiceUtils.loadSortedService(SPIServiceUtils.java:79)
+```
+
 #### 用户登录
 使用zhengyangyong登录:
 
@@ -270,4 +191,8 @@ public ResponseEntity<Boolean> changePassword(@RequestBody UserUpdateDTO userUpd
 
 修改密码成功。
 
-**这里可能有疑问,使用zhengyangyong登录后,是可以通过这个Token修改其他用户例如lidagang的密码的,这是因为我们目前构建的validate仅检查Token的有效性,而不做权限检查,基于RBAC的角色权限管理系统将会在未来构建。**
\ No newline at end of file
+**这里可能有疑问,使用zhengyangyong登录后,是可以通过这个Token修改其他用户例如lidagang的密码的,这是因为我们目前构建的validate仅检查Token的有效性,而不做权限检查,基于RBAC的角色权限管理系统将会在未来构建。**
+
+### 参考资料
+1. AuthenticationFilter的完整[代码](https://github.com/zhengyangyong/scaffold/blob/master/edge-service/src/main/java/org/apache/servicecomb/scaffold/edge/filter/AuthenticationFilter.java);
+2. HttpServerFilter的[介绍](https://github.com/apache/incubator-servicecomb-docs/blob/master/java-chassis-reference/zh_CN/general-development/http-filter.md)。
\ No newline at end of file
diff --git a/assets/images/scaffold/FilterChain.png b/assets/images/scaffold/FilterChain.png
index 717c07e..91385df 100644
Binary files a/assets/images/scaffold/FilterChain.png and b/assets/images/scaffold/FilterChain.png differ


[incubator-servicecomb-website] 02/03: fix style mistake

Posted by ni...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ningjiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-servicecomb-website.git

commit 9f20aca7ac3a167d1919395b2b71d1d60bce9376
Author: zhengyangyong <ya...@huawei.com>
AuthorDate: Mon Jul 9 14:10:02 2018 +0800

    fix style mistake
    
    Signed-off-by: zhengyangyong <ya...@huawei.com>
---
 _posts/cn/2018-07-10-easy-build-microservice-system-part-IV.md | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/_posts/cn/2018-07-10-easy-build-microservice-system-part-IV.md b/_posts/cn/2018-07-10-easy-build-microservice-system-part-IV.md
index 5860f57..e79ba84 100644
--- a/_posts/cn/2018-07-10-easy-build-microservice-system-part-IV.md
+++ b/_posts/cn/2018-07-10-easy-build-microservice-system-part-IV.md
@@ -25,7 +25,8 @@ redirect_from:
 | logon    | 新用户注册                  |
 
 除此之外其他业务请求都需要做Token认证;
-3. Edge服务转发访问请求之前,对需要认证的请求先做统一认证,认证通过之后才转发,为了能够未来更好的扩展这种“转发前处理”的能力,我们设计一个处理链机制——`FilterChain`:
+
+3. Edge服务转发访问请求之前,对需要认证的请求先做统一认证,认证通过之后才转发,为了能够未来更好的扩展这种“转发前处理”的能力,我们设计一个处理链机制`FilterChain`:
 
 ![FilterChain](/assets/images/scaffold/FilterChain.png)