You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by ma...@apache.org on 2019/08/08 01:30:03 UTC

[servicecomb-samples] 24/43: 支持refresh流程

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

mabin pushed a commit to branch houserush-sample
in repository https://gitbox.apache.org/repos/asf/servicecomb-samples.git

commit 2ed65addee6f3c0e4382dd2da96b3fe1b0ce8f34
Author: liubao <ba...@huawei.com>
AuthorDate: Fri May 24 14:30:42 2019 +0800

    支持refresh流程
---
 authentication/README.md                           |  18 ++++
 .../server/PasswordTokenGranter.java               | 100 +++++++++++++++++++++
 .../server/RefreshTokenTokenGranter.java           |  95 ++++++++++++++++++++
 .../authentication/server/TokenEndpoint.java       |  54 ++---------
 .../authentication/server/TokenGranter.java}       |  24 +++--
 .../authentication/server/TokenConst.java          |   8 +-
 .../authentication/edge/AuthHandler.java           |   2 +-
 .../resource/ResourceAuthHandler.java              |   2 +-
 .../AuthenticationConfiguration.java               |   6 ++
 .../authentication/AuthenticationTestCase.java     |  54 +++++++++++
 .../gateway/AuthenticationConfiguration.java       |   6 +-
 .../resource/AuthenticationConfiguration.java      |   6 +-
 12 files changed, 313 insertions(+), 62 deletions(-)

diff --git a/authentication/README.md b/authentication/README.md
index 6d477bb..c91d67e 100644
--- a/authentication/README.md
+++ b/authentication/README.md
@@ -90,3 +90,21 @@ http://localhost:9093/v1/test/start
 # TODO LIST
 1. provide TLS for authentication server & edge service
 2. grant scope for INTERNAL access & EXTERNAL access 
+3. access token support: a. use access token to get optional scope or roles token. 这个可以解决角色过多的时候, token过大的一些问题
+4. 实现注销逻辑(会话管理)
+5. 支持分层的角色机制
+
+       ROLE_LEVEL1
+        /       \
+   ROLE_LEVEL2  ROLE_LEVEL2
+
+ TOKEN里面只返回ROLE_LEVEL1,设置为ROLE_LEVEL2访问的操作,也可以访问。
+
+6. REFRESH_TOKEN可以用来实现申请不同SCOPE的TOKEN。 
+7. 设计目标:无状态。认证服务器和资源服务器均可以多实例部署,每个实例之间不共享状态。在实现很多功能的时候,都遵循这个约束。包括通过refresh token获取新的access token的时候。遵循这个约束,意味着请求需要同时传递refresh token和access token。 
+8, 重新设计TOKEN(代码重构、支持会话管理),支持OpenID Connect。
+
+OAUTH的不好的地方:TOKEN在有效期内,容易被利用,无法注销;TOKEN过期后,必须重新认证,和用户是否在一直操作无关,体验不好,虽然可以通过refresh_token获取新的token提升体验,但是refresh_token有效期如果设置的太长,会降低安全性。Token在有效期内,如果修改了权限等信息,无法及时感知,需要重新登录。
+OAUTH的好的地方:TOKEN签发、认证都可以由微服务实例独自完成,不需要共用的数据存储,比如数据库、Redis等,效率更高,弹性扩容。
+
+
diff --git a/authentication/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/PasswordTokenGranter.java b/authentication/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/PasswordTokenGranter.java
new file mode 100644
index 0000000..7d16268
--- /dev/null
+++ b/authentication/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/PasswordTokenGranter.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.server;
+
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.servicecomb.authentication.jwt.JWTClaims;
+import org.apache.servicecomb.authentication.jwt.JsonParser;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.jwt.Jwt;
+import org.springframework.security.jwt.JwtHelper;
+import org.springframework.security.jwt.crypto.sign.Signer;
+import org.springframework.stereotype.Component;
+
+import com.netflix.config.DynamicPropertyFactory;
+
+@Component(value = "passwordTokenGranter")
+public class PasswordTokenGranter implements TokenGranter {
+  @Autowired
+  @Qualifier("authUserDetailsService")
+  private UserDetailsService userDetailsService;
+
+  @Autowired
+  @Qualifier("authPasswordEncoder")
+  private PasswordEncoder passwordEncoder;
+
+  @Autowired
+  @Qualifier("authSigner")
+  private Signer signer;
+
+  @Override
+  public Token grant(Map<String, String> parameters) {
+    String username = parameters.get(TokenConst.PARAM_USERNAME);
+    String password = parameters.get(TokenConst.PARAM_PASSWORD);
+
+    UserDetails userDetails = userDetailsService.loadUserByUsername(username);
+    if (passwordEncoder.matches(password, userDetails.getPassword())) {
+      JWTClaims claims = new JWTClaims();
+      if (userDetails.getAuthorities() != null) {
+        userDetails.getAuthorities().forEach(authority -> claims.addAuthority(authority.getAuthority()));
+      }
+      claims.setJti(UUID.randomUUID().toString());
+      claims.setIat(System.currentTimeMillis());
+      claims.setExp(5 * 60);
+      
+      String content = JsonParser.unparse(claims);
+      Jwt accessToken = JwtHelper.encode(content, signer);
+
+      Token token = new Token();
+      token.setScope(claims.getScope());
+      token.setExpires_in(10 * 60);
+      token.setToken_type("bearer");
+      token.setAccess_token(accessToken.getEncoded());
+      
+      JWTClaims accessTokenClaims = new JWTClaims();
+      accessTokenClaims.setJti(UUID.randomUUID().toString());
+      accessTokenClaims.setIat(System.currentTimeMillis());
+      accessTokenClaims.setExp(60 * 60);
+      Jwt refreshToken = JwtHelper.encode(JsonParser.unparse(claims), signer);
+      token.setRefresh_token(refreshToken.getEncoded());
+      
+      return token;
+    } else {
+      return null;
+    }
+  }
+
+  @Override
+  public String grantType() {
+    return TokenConst.GRANT_TYPE_PASSWORD;
+  }
+
+  @Override
+  public boolean enabled() {
+    return DynamicPropertyFactory.getInstance()
+        .getBooleanProperty("servicecomb.authentication.granter.password.enabled", true)
+        .get();
+  }
+
+}
diff --git a/authentication/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/RefreshTokenTokenGranter.java b/authentication/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/RefreshTokenTokenGranter.java
new file mode 100644
index 0000000..ffbf9c5
--- /dev/null
+++ b/authentication/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/RefreshTokenTokenGranter.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.server;
+
+import java.util.Map;
+
+import org.apache.servicecomb.authentication.jwt.JWTClaims;
+import org.apache.servicecomb.authentication.jwt.JsonParser;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.security.jwt.Jwt;
+import org.springframework.security.jwt.JwtHelper;
+import org.springframework.security.jwt.crypto.sign.Signer;
+import org.springframework.security.jwt.crypto.sign.SignerVerifier;
+import org.springframework.stereotype.Component;
+
+import com.netflix.config.DynamicPropertyFactory;
+
+@Component(value = "fefreshTokenTokenGranter")
+public class RefreshTokenTokenGranter implements TokenGranter {
+  @Autowired
+  @Qualifier("authSignerVerifier")
+  private SignerVerifier signerVerifier;
+
+  @Autowired
+  @Qualifier("authSigner")
+  private Signer signer;
+
+  @Override
+  public boolean enabled() {
+    return DynamicPropertyFactory.getInstance()
+        .getBooleanProperty("servicecomb.authentication.granter.refreshToken.enabled", true)
+        .get();
+  }
+
+  @Override
+  public String grantType() {
+    return TokenConst.GRANT_TYPE_REFRESH_TOKEN;
+  }
+
+  @Override
+  public Token grant(Map<String, String> parameters) {
+    String refreshToken = parameters.get(TokenConst.PARAM_REFRESH_TOKEN);
+    String accessToken = parameters.get(TokenConst.PARAM_ACCESS_TOKEN);
+
+    // verify refresh tokens
+    Jwt jwt = JwtHelper.decode(refreshToken);
+    JWTClaims claims;
+    try {
+      jwt.verifySignature(signerVerifier);
+      claims = JsonParser.parse(jwt.getClaims(), JWTClaims.class);
+      // TODO: verify claims.
+    } catch (Exception e) {
+      return null;
+    }
+
+    // verify access tokens
+    jwt = JwtHelper.decode(accessToken);
+    claims = null;
+    try {
+      jwt.verifySignature(signerVerifier);
+      claims = JsonParser.parse(jwt.getClaims(), JWTClaims.class);
+      // TODO: verify claims.
+    } catch (Exception e) {
+      return null;
+    }
+
+    claims.setIat(System.currentTimeMillis());
+    String content = JsonParser.unparse(claims);
+    Jwt newAccessToken = JwtHelper.encode(content, signer);
+
+    Token token = new Token();
+    token.setScope(claims.getScope());
+    token.setExpires_in(10 * 60);
+    token.setToken_type("bearer");
+    token.setAccess_token(newAccessToken.getEncoded());
+    return token;
+  }
+
+}
diff --git a/authentication/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenEndpoint.java b/authentication/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenEndpoint.java
index 67c7ba4..775d332 100644
--- a/authentication/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenEndpoint.java
+++ b/authentication/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenEndpoint.java
@@ -17,23 +17,13 @@
 
 package org.apache.servicecomb.authentication.server;
 
+import java.util.List;
 import java.util.Map;
 
 import javax.ws.rs.core.MediaType;
 
-import org.apache.servicecomb.authentication.jwt.JWTClaims;
-import org.apache.servicecomb.authentication.jwt.JsonParser;
 import org.apache.servicecomb.provider.rest.common.RestSchema;
-import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
-import org.springframework.security.crypto.password.PasswordEncoder;
-import org.springframework.security.jwt.Jwt;
-import org.springframework.security.jwt.JwtHelper;
-import org.springframework.security.jwt.crypto.sign.Signer;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -42,53 +32,23 @@ import org.springframework.web.bind.annotation.RequestMapping;
 @RequestMapping(path = "/v1/oauth/token")
 public class TokenEndpoint implements TokenService {
   @Autowired
-  @Qualifier("authUserDetailsService")
-  private UserDetailsService userDetailsService;
-
-  @Autowired
-  @Qualifier("authPasswordEncoder")
-  private PasswordEncoder passwordEncoder;
-
-  @Autowired
-  @Qualifier("authSigner")
-  private Signer signer;
+  private List<TokenGranter> granters;
 
   @Override
   @PostMapping(path = "/", consumes = MediaType.APPLICATION_FORM_URLENCODED)
   public Token getAccessToken(@RequestBody Map<String, String> parameters) {
     String grantType = parameters.get(TokenConst.PARAM_GRANT_TYPE);
 
-    if (TokenConst.GRANT_TYPE_PASSWORD.equals(grantType)) {
-
-      String username = parameters.get(TokenConst.PARAM_USERNAME);
-      String password = parameters.get(TokenConst.PARAM_PASSWORD);
-
-      try {
-        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
-        if (passwordEncoder.matches(password, userDetails.getPassword())) {
-          JWTClaims claims = new JWTClaims();
-          if (userDetails.getAuthorities() != null) {
-            userDetails.getAuthorities().forEach(authority -> claims.addAuthority(authority.getAuthority()));
-          }
-          String content = JsonParser.unparse(claims);
-          Jwt accessToken = JwtHelper.encode(content, signer);
-
-          Token token = new Token();
-          token.setScope(claims.getScope());
-          token.setExpires_in(10 * 60);
-          token.setToken_type("bearer");
-          token.setAccess_token(accessToken.getEncoded());
+    for (TokenGranter granter : granters) {
+      if (granter.enabled()) {
+        Token token = granter.grant(grantType, parameters);
+        if (token != null) {
           return token;
-        } else {
-          return null;
         }
-      } catch (UsernameNotFoundException e) {
-        throw new InvocationException(403, "", "forbidden");
       }
-    } else {
-      return null;
     }
 
+    return null;
   }
 
 }
diff --git a/authentication/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenConst.java b/authentication/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenGranter.java
similarity index 67%
copy from authentication/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenConst.java
copy to authentication/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenGranter.java
index a46a7b9..9ba0861 100644
--- a/authentication/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenConst.java
+++ b/authentication/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenGranter.java
@@ -17,12 +17,24 @@
 
 package org.apache.servicecomb.authentication.server;
 
-public class TokenConst {
-  public static final String PARAM_GRANT_TYPE = "grant_type";
+import java.util.Map;
 
-  public static final String PARAM_USERNAME = "username";
+/**
+ * Token granter is used to grant access tokens. 
+ * @author Administrator
+ *
+ */
+public interface TokenGranter {
+  boolean enabled();
+
+  String grantType();
+
+  default Token grant(String grantType, Map<String, String> parameters) {
+    if (grantType().equals(grantType)) {
+      return grant(parameters);
+    }
+    return null;
+  }
 
-  public static final String PARAM_PASSWORD = "password";
-  
-  public static final String GRANT_TYPE_PASSWORD = "password";
+  Token grant(Map<String, String> parameters);
 }
diff --git a/authentication/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenConst.java b/authentication/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenConst.java
index a46a7b9..915a515 100644
--- a/authentication/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenConst.java
+++ b/authentication/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenConst.java
@@ -23,6 +23,12 @@ public class TokenConst {
   public static final String PARAM_USERNAME = "username";
 
   public static final String PARAM_PASSWORD = "password";
-  
+
+  public static final String PARAM_REFRESH_TOKEN = "refresh_token";
+
+  public static final String PARAM_ACCESS_TOKEN = "access_token";
+
   public static final String GRANT_TYPE_PASSWORD = "password";
+  
+  public static final String GRANT_TYPE_REFRESH_TOKEN = "refresh_token";
 }
diff --git a/authentication/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/AuthHandler.java b/authentication/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/AuthHandler.java
index 2c8d63c..40ef32d 100644
--- a/authentication/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/AuthHandler.java
+++ b/authentication/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/AuthHandler.java
@@ -38,7 +38,7 @@ public class AuthHandler implements Handler {
     }
     Jwt jwt = JwtHelper.decode(token);
     try {
-      jwt.verifySignature(BeanUtils.getBean("authSigner"));
+      jwt.verifySignature(BeanUtils.getBean("authSignerVerifier"));
     } catch (InvalidSignatureException e) {
       asyncResponse.consumerFail(new InvocationException(403, "forbidden", "not authenticated"));
       return;
diff --git a/authentication/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java b/authentication/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java
index 37de72d..1d8e32b 100644
--- a/authentication/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java
+++ b/authentication/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java
@@ -59,7 +59,7 @@ public class ResourceAuthHandler implements Handler {
     Jwt jwt = JwtHelper.decode(token);
     JWTClaims claims;
     try {
-      jwt.verifySignature(BeanUtils.getBean("authSigner"));
+      jwt.verifySignature(BeanUtils.getBean("authSignerVerifier"));
       claims = JsonParser.parse(jwt.getClaims(), JWTClaims.class);
       // TODO: verify claims.
     } catch (Exception e) {
diff --git a/authentication/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java b/authentication/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java
index 7d9d076..2fdbd4c 100644
--- a/authentication/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java
+++ b/authentication/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java
@@ -31,6 +31,7 @@ import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
 import org.springframework.security.jwt.crypto.sign.MacSigner;
 import org.springframework.security.jwt.crypto.sign.Signer;
+import org.springframework.security.jwt.crypto.sign.SignerVerifier;
 import org.springframework.security.provisioning.InMemoryUserDetailsManager;
 
 @Configuration
@@ -46,6 +47,11 @@ public class AuthenticationConfiguration {
 
   @Bean(name = "authSigner")
   public Signer authSigner() {
+    return authSignerVerifier();
+  }
+  
+  @Bean(name = "authSignerVerifier")
+  public SignerVerifier authSignerVerifier() {
     return new MacSigner("Please change this key.");
   }
 
diff --git a/authentication/samples/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationTestCase.java b/authentication/samples/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationTestCase.java
index 50a4519..13bfaba 100644
--- a/authentication/samples/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationTestCase.java
+++ b/authentication/samples/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationTestCase.java
@@ -17,10 +17,13 @@
 
 package org.apache.servicecomb.authentication;
 
+import org.apache.servicecomb.authentication.jwt.JWTClaims;
+import org.apache.servicecomb.authentication.jwt.JsonParser;
 import org.apache.servicecomb.authentication.server.Token;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
+import org.springframework.security.jwt.JwtHelper;
 import org.springframework.stereotype.Component;
 import org.springframework.util.LinkedMultiValueMap;
 import org.springframework.util.MultiValueMap;
@@ -80,6 +83,56 @@ public class AuthenticationTestCase implements TestCase {
       TestMgr.check(403, e.getStatusCode().value());
     }
     TestMgr.check(null, name);
+    
+    // refresh token
+    // get token
+    map = new LinkedMultiValueMap<>();
+    map.add("grant_type", "refresh_token");
+    map.add("refresh_token", token.getRefresh_token());
+    map.add("access_token", token.getAccess_token());
+    headers = new HttpHeaders();
+    headers.setContentType(MediaType.MULTIPART_FORM_DATA);
+
+    Token tokenNew =
+        BootEventListener.authenticationServerTokenEndpoint.postForObject("/",
+            new HttpEntity<>(map, headers),
+            Token.class);
+    TestMgr.check(token.getToken_type(), tokenNew.getToken_type());
+   
+    JWTClaims claims = JsonParser.parse(JwtHelper.decode(token.getAccess_token()).getClaims(), JWTClaims.class);
+    JWTClaims newClaims = JsonParser.parse(JwtHelper.decode(tokenNew.getAccess_token()).getClaims(), JWTClaims.class);
+    TestMgr.check(claims.getJti(), newClaims.getJti());
+    TestMgr.check(claims.getIat() < newClaims.getIat(), true);
+
+    // get resources
+    headers = new HttpHeaders();
+    headers.add("Authorization", "Bearer " + tokenNew.getAccess_token());
+    headers.setContentType(MediaType.APPLICATION_JSON);
+
+    name = BootEventListener.resouceServerHandlerAuthEndpoint.postForObject("/everyoneSayHello?name=Hi",
+        new HttpEntity<>(headers),
+        String.class);
+    TestMgr.check("Hi", name);
+
+    name = BootEventListener.resouceServerHandlerAuthEndpoint.postForObject("/adminSayHello?name=Hi",
+        new HttpEntity<>(headers),
+        String.class);
+    TestMgr.check("Hi", name);
+
+    name = BootEventListener.resouceServerHandlerAuthEndpoint.postForObject("/guestOrAdminSayHello?name=Hi",
+        new HttpEntity<>(headers),
+        String.class);
+    TestMgr.check("Hi", name);
+
+    name = null;
+    try {
+      name = BootEventListener.resouceServerHandlerAuthEndpoint.postForObject("/guestSayHello?name=Hi",
+          new HttpEntity<>(headers),
+          String.class);
+    } catch (HttpClientErrorException e) {
+      TestMgr.check(403, e.getStatusCode().value());
+    }
+    TestMgr.check(null, name);
   }
 
 
@@ -98,6 +151,7 @@ public class AuthenticationTestCase implements TestCase {
             Token.class);
     TestMgr.check("bearer", token.getToken_type());
     TestMgr.check(true, token.getAccess_token().length() > 10);
+    TestMgr.check(true, token.getRefresh_token().length() > 10);
 
     // get resources
     headers = new HttpHeaders();
diff --git a/authentication/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationConfiguration.java b/authentication/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationConfiguration.java
index 87837eb..1e913fb 100644
--- a/authentication/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationConfiguration.java
+++ b/authentication/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationConfiguration.java
@@ -20,12 +20,12 @@ package org.apache.servicecomb.authentication.gateway;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.security.jwt.crypto.sign.MacSigner;
-import org.springframework.security.jwt.crypto.sign.Signer;
+import org.springframework.security.jwt.crypto.sign.SignerVerifier;
 
 @Configuration
 public class AuthenticationConfiguration {
-  @Bean(name = "authSigner")
-  public Signer authSigner() {
+  @Bean(name = "authSignerVerifier")
+  public SignerVerifier authSignerVerifier() {
     return new MacSigner("Please change this key.");
   }
 }
diff --git a/authentication/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java b/authentication/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java
index 0e58c30..712030d 100644
--- a/authentication/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java
+++ b/authentication/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java
@@ -20,12 +20,12 @@ package org.apache.servicecomb.authentication.resource;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.security.jwt.crypto.sign.MacSigner;
-import org.springframework.security.jwt.crypto.sign.Signer;
+import org.springframework.security.jwt.crypto.sign.SignerVerifier;
 
 @Configuration
 public class AuthenticationConfiguration {
-  @Bean(name = "authSigner")
-  public Signer authSigner() {
+  @Bean(name = "authSignerVerifier")
+  public SignerVerifier authSignerVerifier() {
     return new MacSigner("Please change this key.");
   }
 }