Преглед изворни кода

完成 oauth2 password 密码模式的实现
完成 oauth2 revokeToken 的实现

YunaiV пре 3 година
родитељ
комит
0900b9e111
11 измењених фајлова са 228 додато и 44 уклоњено
  1. 21 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2Controller.http
  2. 53 10
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.java
  3. 3 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenAccessTokenRespVO.java
  4. 1 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/oauth2/OAuth2OpenConvert.java
  5. 1 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/security/config/SecurityConfiguration.java
  6. 10 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java
  7. 23 23
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java
  8. 58 1
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantService.java
  9. 39 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantServiceImpl.java
  10. 10 1
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/util/oauth2/OAuth2Utils.java
  11. 9 9
      yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java

+ 21 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2Controller.http

@@ -21,3 +21,24 @@ Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw==
 tenant-id: {{adminTenentId}}
 
 grant_type=authorization_code&redirect_uri=https://www.iocoder.cn
+
+### 请求 /system/oauth2/token + password 接口 => 成功
+POST {{baseUrl}}/system/oauth2/token
+Content-Type: application/x-www-form-urlencoded
+Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw==
+tenant-id: {{adminTenentId}}
+
+grant_type=password&username=admin&password=admin123&scope=user_info
+
+### 请求 /system/oauth2/token + refresh_token 接口 => 成功
+POST {{baseUrl}}/system/oauth2/token
+Content-Type: application/x-www-form-urlencoded
+Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw==
+tenant-id: {{adminTenentId}}
+
+grant_type=refresh_token&refresh_token=00895465d6994f72a9d926ceeed0f588
+
+### 请求 /system/oauth2/token + DELETE 接口 => 成功
+DELETE {{baseUrl}}/system/oauth2/token?token=ca8a188f464441d6949c51493a2b7596
+Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw==
+tenant-id: {{adminTenentId}}

+ 53 - 10
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.java

@@ -47,8 +47,6 @@ public class OAuth2OpenController {
 
 //    POST oauth/check_token CheckTokenEndpoint
 
-//    DELETE oauth/token ConsumerTokenServices#revokeToken
-
     @Resource
     private OAuth2GrantService oauth2GrantService;
     @Resource
@@ -56,20 +54,38 @@ public class OAuth2OpenController {
     @Resource
     private OAuth2ApproveService oauth2ApproveService;
 
+    /**
+     * 对应 Spring Security OAuth 的 TokenEndpoint 类的 postAccessToken 方法
+     *
+     * 授权码 authorization_code 模式时:code + redirectUri + state 参数
+     * 密码 password 模式时:username + password + scope 参数
+     * 刷新 refresh_token 模式时:refreshToken 参数
+     * 客户端 client_credentials 模式:scope 参数
+     * 简化 implicit 模式时:不支持
+     *
+     * 注意,默认需要传递 client_id + client_secret 参数
+     */
     @PostMapping("/token")
     @ApiOperation(value = "获得访问令牌", notes = "适合 code 授权码模式,或者 implicit 简化模式;在 authorize.vue 单点登录界面被【获取】调用")
     @ApiImplicitParams({
             @ApiImplicitParam(name = "grant_type", required = true, value = "授权类型", example = "code", dataTypeClass = String.class),
             @ApiImplicitParam(name = "code", value = "授权范围", example = "userinfo.read", dataTypeClass = String.class),
             @ApiImplicitParam(name = "redirect_uri", value = "重定向 URI", example = "https://www.iocoder.cn", dataTypeClass = String.class),
-            @ApiImplicitParam(name = "state", example = "123321", dataTypeClass = String.class)
+            @ApiImplicitParam(name = "username", example = "tudou", dataTypeClass = String.class),
+            @ApiImplicitParam(name = "password", example = "cai", dataTypeClass = String.class), // 多个使用空格分隔
+            @ApiImplicitParam(name = "scope", example = "user_info", dataTypeClass = String.class)
     })
     @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
     public CommonResult<OAuth2OpenAccessTokenRespVO> postAccessToken(HttpServletRequest request,
                                                                      @RequestParam("grant_type") String grantType,
                                                                      @RequestParam(value = "code", required = false) String code, // 授权码模式
                                                                      @RequestParam(value = "redirect_uri", required = false) String redirectUri, // 授权码模式
-                                                                     @RequestParam(value = "state", required = false) String state) { // 授权码模式
+                                                                     @RequestParam(value = "state", required = false) String state, // 授权码模式
+                                                                     @RequestParam(value = "username", required = false) String username, // 密码模式
+                                                                     @RequestParam(value = "password", required = false) String password, // 密码模式
+                                                                     @RequestParam(value = "scope", required = false) String scope, // 密码模式
+                                                                     @RequestParam(value = "refresh_token", required = false) String refreshToken) { // 刷新模式
+        List<String> scopes = OAuth2Utils.buildScopes(scope);
         // 授权类型
         OAuth2GrantTypeEnum grantTypeEnum = OAuth2GrantTypeEnum.getByGranType(grantType);
         if (grantTypeEnum == null) {
@@ -80,23 +96,24 @@ public class OAuth2OpenController {
         }
 
         // 校验客户端
-        String[] clientIdAndSecret = HttpUtils.obtainBasicAuthorization(request);
-        if (ArrayUtil.isEmpty(clientIdAndSecret) || clientIdAndSecret.length != 2) {
-            throw exception0(BAD_REQUEST.getCode(), "client_id 或 client_secret 未正确传递");
-        }
-        OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientIdAndSecret[0], clientIdAndSecret[1], grantType, null, null);
+        String[] clientIdAndSecret = obtainBasicAuthorization(request);
+        OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientIdAndSecret[0], clientIdAndSecret[1],
+                grantType, scopes, redirectUri);
 
         // 根据授权模式,获取访问令牌
-        OAuth2AccessTokenDO accessTokenDO = null;
+        OAuth2AccessTokenDO accessTokenDO;
         switch (grantTypeEnum) {
             case AUTHORIZATION_CODE:
                 accessTokenDO = oauth2GrantService.grantAuthorizationCodeForAccessToken(client.getClientId(), code, redirectUri, state);
                 break;
             case PASSWORD:
+                accessTokenDO = oauth2GrantService.grantPassword(username, password, client.getClientId(), scopes);
                 break;
             case CLIENT_CREDENTIALS:
+                accessTokenDO = oauth2GrantService.grantClientCredentials(client.getClientId(), scopes);
                 break;
             case REFRESH_TOKEN:
+                accessTokenDO = oauth2GrantService.grantRefreshToken(refreshToken, client.getClientId());
                 break;
             default:
                 throw new IllegalArgumentException("未知授权类型:" + grantType);
@@ -105,6 +122,24 @@ public class OAuth2OpenController {
         return success(OAuth2OpenConvert.INSTANCE.convert(accessTokenDO));
     }
 
+    @DeleteMapping("/token")
+    @ApiOperation(value = "删除访问令牌")
+    @ApiImplicitParam(name = "token", required = true, value = "访问令牌", example = "biu", dataTypeClass = String.class)
+    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
+    public CommonResult<Boolean> revokeToken(HttpServletRequest request,
+                                             @RequestParam("token") String token) {
+        // 校验客户端
+        String[] clientIdAndSecret = obtainBasicAuthorization(request);
+        if (ArrayUtil.isEmpty(clientIdAndSecret) || clientIdAndSecret.length != 2) {
+            throw exception0(BAD_REQUEST.getCode(), "client_id 或 client_secret 未正确传递");
+        }
+        OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientIdAndSecret[0], clientIdAndSecret[1],
+                null, null, null);
+
+        // 删除访问令牌
+        return success(oauth2GrantService.revokeToken(client.getClientId(), token));
+    }
+
     //    GET  oauth/authorize AuthorizationEndpoint TODO
     @GetMapping("/authorize")
     @ApiOperation(value = "获得授权信息", notes = "适合 code 授权码模式,或者 implicit 简化模式;在 authorize.vue 单点登录界面被【获取】调用")
@@ -229,4 +264,12 @@ public class OAuth2OpenController {
         return UserTypeEnum.ADMIN.getValue();
     }
 
+    private String[] obtainBasicAuthorization(HttpServletRequest request) {
+        String[] clientIdAndSecret = HttpUtils.obtainBasicAuthorization(request);
+        if (ArrayUtil.isEmpty(clientIdAndSecret) || clientIdAndSecret.length != 2) {
+            throw exception0(BAD_REQUEST.getCode(), "client_id 或 client_secret 未正确传递");
+        }
+        return clientIdAndSecret;
+    }
+
 }

+ 3 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenAccessTokenRespVO.java

@@ -29,4 +29,7 @@ public class OAuth2OpenAccessTokenRespVO {
     @JsonProperty("expires_in")
     private Long expiresIn;
 
+    @ApiModelProperty(value = "授权范围", example = "user_info", notes = "如果多个授权范围,使用空格分隔")
+    private String scope;
+
 }

+ 1 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/oauth2/OAuth2OpenConvert.java

@@ -16,6 +16,7 @@ public interface OAuth2OpenConvert {
         OAuth2OpenAccessTokenRespVO respVO = convert0(bean);
         respVO.setTokenType(SecurityFrameworkUtils.AUTHORIZATION_BEARER.toLowerCase());
         respVO.setExpiresIn(OAuth2Utils.getExpiresIn(bean.getExpiresTime()));
+        respVO.setScope(OAuth2Utils.buildScopeStr(bean.getScopes()));
         return respVO;
     }
 

+ 1 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/security/config/SecurityConfiguration.java

@@ -37,6 +37,7 @@ public class SecurityConfiguration {
                 registry.antMatchers(buildAdminApi("/system/sms/callback/**")).permitAll();
                 // OAuth2 API
                 registry.antMatchers(buildAdminApi("/system/oauth2/token")).permitAll();
+                registry.antMatchers(buildAdminApi("/system/oauth2/check_token")).permitAll();
             }
 
         };

+ 10 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java

@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.module.system.service.auth;
 
 import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*;
+import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
 
 import javax.validation.Valid;
 
@@ -13,6 +14,15 @@ import javax.validation.Valid;
  */
 public interface AdminAuthService {
 
+    /**
+     * 验证账号 + 密码。如果通过,则返回用户
+     *
+     * @param username 账号
+     * @param password 密码
+     * @return 用户
+     */
+    AdminUserDO authenticate(String username, String password);
+
     /**
      * 账号登录
      *

+ 23 - 23
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java

@@ -62,13 +62,34 @@ public class AdminAuthServiceImpl implements AdminAuthService {
     @Resource
     private SmsCodeApi smsCodeApi;
 
+    @Override
+    public AdminUserDO authenticate(String username, String password) {
+        final LoginLogTypeEnum logTypeEnum = LoginLogTypeEnum.LOGIN_USERNAME;
+        // 校验账号是否存在
+        AdminUserDO user = userService.getUserByUsername(username);
+        if (user == null) {
+            createLoginLog(null, username, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS);
+            throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
+        }
+        if (!userService.isPasswordMatch(password, user.getPassword())) {
+            createLoginLog(user.getId(), username, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS);
+            throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
+        }
+        // 校验是否禁用
+        if (ObjectUtil.notEqual(user.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
+            createLoginLog(user.getId(), username, logTypeEnum, LoginResultEnum.USER_DISABLED);
+            throw exception(AUTH_LOGIN_USER_DISABLED);
+        }
+        return user;
+    }
+
     @Override
     public AuthLoginRespVO login(AuthLoginReqVO reqVO) {
         // 判断验证码是否正确
         verifyCaptcha(reqVO);
 
         // 使用账号密码,进行登录
-        AdminUserDO user = login0(reqVO.getUsername(), reqVO.getPassword());
+        AdminUserDO user = authenticate(reqVO.getUsername(), reqVO.getPassword());
 
         // 创建 Token 令牌,记录登录日志
         return createTokenAfterLoginSuccess(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME);
@@ -125,27 +146,6 @@ public class AdminAuthServiceImpl implements AdminAuthService {
         captchaService.deleteCaptchaCode(reqVO.getUuid());
     }
 
-    @VisibleForTesting
-    AdminUserDO login0(String username, String password) {
-        final LoginLogTypeEnum logTypeEnum = LoginLogTypeEnum.LOGIN_USERNAME;
-        // 校验账号是否存在
-        AdminUserDO user = userService.getUserByUsername(username);
-        if (user == null) {
-            createLoginLog(null, username, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS);
-            throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
-        }
-        if (!userService.isPasswordMatch(password, user.getPassword())) {
-            createLoginLog(user.getId(), username, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS);
-            throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
-        }
-        // 校验是否禁用
-        if (ObjectUtil.notEqual(user.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
-            createLoginLog(user.getId(), username, logTypeEnum, LoginResultEnum.USER_DISABLED);
-            throw exception(AUTH_LOGIN_USER_DISABLED);
-        }
-        return user;
-    }
-
     private void createLoginLog(Long userId, String username,
                                 LoginLogTypeEnum logTypeEnum, LoginResultEnum loginResult) {
         // 插入登录日志
@@ -187,7 +187,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
     @Override
     public AuthLoginRespVO socialBindLogin(AuthSocialBindLoginReqVO reqVO) {
         // 使用账号密码,进行登录。
-        AdminUserDO user = login0(reqVO.getUsername(), reqVO.getPassword());
+        AdminUserDO user = authenticate(reqVO.getUsername(), reqVO.getPassword());
 
         // 绑定社交用户
         socialUserService.bindSocialUser(AuthConvert.INSTANCE.convert(user.getId(), getUserType().getValue(), reqVO));

+ 58 - 1
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantService.java

@@ -18,7 +18,17 @@ import java.util.List;
  */
 public interface OAuth2GrantService {
 
-    // ImplicitTokenGranter
+    /**
+     * 简化模式
+     *
+     * 对应 Spring Security OAuth2 的 ImplicitTokenGranter 功能
+     *
+     * @param userId 用户编号
+     * @param userType 用户类型
+     * @param clientId 客户端编号
+     * @param scopes 授权范围
+     * @return 访问令牌
+     */
     OAuth2AccessTokenDO grantImplicit(Long userId, Integer userType,
                                       String clientId, List<String> scopes);
 
@@ -53,4 +63,51 @@ public interface OAuth2GrantService {
     OAuth2AccessTokenDO grantAuthorizationCodeForAccessToken(String clientId, String code,
                                                              String redirectUri, String state);
 
+    /**
+     * 密码模式
+     *
+     * 对应 Spring Security OAuth2 的 ResourceOwnerPasswordTokenGranter 功能
+     *
+     * @param username 账号
+     * @param password 密码
+     * @param clientId 客户端编号
+     * @param scopes 授权范围
+     * @return 访问令牌
+     */
+    OAuth2AccessTokenDO grantPassword(String username, String password,
+                                      String clientId, List<String> scopes);
+
+    /**
+     * 刷新模式
+     *
+     * 对应 Spring Security OAuth2 的 ResourceOwnerPasswordTokenGranter 功能
+     *
+     * @param refreshToken 刷新令牌
+     * @param clientId 客户端编号
+     * @return 访问令牌
+     */
+    OAuth2AccessTokenDO grantRefreshToken(String refreshToken, String clientId);
+
+    /**
+     * 客户端模式
+     *
+     * 对应 Spring Security OAuth2 的 ClientCredentialsTokenGranter 功能
+     *
+     * @param clientId 客户端编号
+     * @param scopes 授权范围
+     * @return 访问令牌
+     */
+    OAuth2AccessTokenDO grantClientCredentials(String clientId, List<String> scopes);
+
+    /**
+     * 移除访问令牌
+     *
+     * 对应 Spring Security OAuth2 的 ConsumerTokenServices 的 revokeToken 方法
+     *
+     * @param accessToken 访问令牌
+     * @param clientId 客户端编号
+     * @return 是否移除到
+     */
+    boolean revokeToken(String clientId, String accessToken);
+
 }

+ 39 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantServiceImpl.java

@@ -1,9 +1,14 @@
 package cn.iocoder.yudao.module.system.service.oauth2;
 
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
 import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2CodeDO;
+import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
 import cn.iocoder.yudao.module.system.enums.ErrorCodeConstants;
+import cn.iocoder.yudao.module.system.service.auth.AdminAuthService;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
@@ -23,6 +28,8 @@ public class OAuth2GrantServiceImpl implements OAuth2GrantService {
 
     @Resource
     private OAuth2TokenService oauth2TokenService;
+    @Resource
+    private AdminAuthService adminAuthService;
 
     @Override
     public OAuth2AccessTokenDO grantImplicit(Long userId, Integer userType,
@@ -65,4 +72,36 @@ public class OAuth2GrantServiceImpl implements OAuth2GrantService {
                 codeDO.getClientId(), codeDO.getScopes());
     }
 
+    @Override
+    public OAuth2AccessTokenDO grantPassword(String username, String password, String clientId, List<String> scopes) {
+        // 使用账号 + 密码进行登录
+        AdminUserDO user = adminAuthService.authenticate(username, password);
+        Assert.notNull(user, "用户不能为空!"); // 防御性编程
+
+        // 创建访问令牌
+        return oauth2TokenService.createAccessToken(user.getId(), UserTypeEnum.ADMIN.getValue(), clientId, scopes);
+    }
+
+    @Override
+    public OAuth2AccessTokenDO grantRefreshToken(String refreshToken, String clientId) {
+        return oauth2TokenService.refreshAccessToken(refreshToken, clientId);
+    }
+
+    @Override
+    public OAuth2AccessTokenDO grantClientCredentials(String clientId, List<String> scopes) {
+        // TODO 芋艿:项目中使用 OAuth2 解决的是三方应用的授权,内部的 SSO 等问题,所以暂时不考虑 client_credentials 这个场景
+        throw new UnsupportedOperationException("暂时不支持 client_credentials 授权模式");
+    }
+
+    @Override
+    public boolean revokeToken(String clientId, String accessToken) {
+        // 先查询,保证 clientId 时匹配的
+        OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.getAccessToken(accessToken);
+        if (accessTokenDO == null || ObjectUtil.notEqual(clientId, accessTokenDO.getClientId())) {
+            return false;
+        }
+        // 再删除
+        return oauth2TokenService.removeAccessToken(accessToken) != null;
+    }
+
 }

+ 10 - 1
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/util/oauth2/OAuth2Utils.java

@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.module.system.util.oauth2;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
 import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
 
@@ -58,7 +59,7 @@ public class OAuth2Utils {
             vars.put("expires_in", getExpiresIn(expireTime));
         }
         if (CollUtil.isNotEmpty(scopes)) {
-            vars.put("scope", CollUtil.join(scopes, " "));
+            vars.put("scope", buildScopeStr(scopes));
         }
         for (String key : additionalInformation.keySet()) {
             Object value = additionalInformation.get(key);
@@ -86,4 +87,12 @@ public class OAuth2Utils {
         return (expireTime.getTime() - System.currentTimeMillis()) / 1000;
     }
 
+    public static String buildScopeStr(Collection<String> scopes) {
+        return CollUtil.join(scopes, " ");
+    }
+
+    public static List<String> buildScopes(String scope) {
+        return StrUtil.split(scope, ' ');
+    }
+
 }

+ 9 - 9
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AuthServiceImplTest.java → yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java

@@ -34,7 +34,7 @@ import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.*;
 
 @Import(AdminAuthServiceImpl.class)
-public class AuthServiceImplTest extends BaseDbUnitTest {
+public class AdminAuthServiceImplTest extends BaseDbUnitTest {
 
     @Resource
     private AdminAuthServiceImpl authService;
@@ -63,7 +63,7 @@ public class AuthServiceImplTest extends BaseDbUnitTest {
     }
 
     @Test
-    public void testLogin0_success() {
+    public void testAuthenticate_success() {
         // 准备参数
         String username = randomString();
         String password = randomString();
@@ -75,19 +75,19 @@ public class AuthServiceImplTest extends BaseDbUnitTest {
         when(userService.isPasswordMatch(eq(password), eq(user.getPassword()))).thenReturn(true);
 
         // 调用
-        AdminUserDO loginUser = authService.login0(username, password);
+        AdminUserDO loginUser = authService.authenticate(username, password);
         // 校验
         assertPojoEquals(user, loginUser);
     }
 
     @Test
-    public void testLogin0_userNotFound() {
+    public void testAuthenticate_userNotFound() {
         // 准备参数
         String username = randomString();
         String password = randomString();
 
         // 调用, 并断言异常
-        AssertUtils.assertServiceException(() -> authService.login0(username, password),
+        AssertUtils.assertServiceException(() -> authService.authenticate(username, password),
                 AUTH_LOGIN_BAD_CREDENTIALS);
         verify(loginLogService).createLoginLog(
                 argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType())
@@ -97,7 +97,7 @@ public class AuthServiceImplTest extends BaseDbUnitTest {
     }
 
     @Test
-    public void testLogin0_badCredentials() {
+    public void testAuthenticate_badCredentials() {
         // 准备参数
         String username = randomString();
         String password = randomString();
@@ -107,7 +107,7 @@ public class AuthServiceImplTest extends BaseDbUnitTest {
         when(userService.getUserByUsername(eq(username))).thenReturn(user);
 
         // 调用, 并断言异常
-        AssertUtils.assertServiceException(() -> authService.login0(username, password),
+        AssertUtils.assertServiceException(() -> authService.authenticate(username, password),
                 AUTH_LOGIN_BAD_CREDENTIALS);
         verify(loginLogService).createLoginLog(
                 argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType())
@@ -117,7 +117,7 @@ public class AuthServiceImplTest extends BaseDbUnitTest {
     }
 
     @Test
-    public void testLogin0_userDisabled() {
+    public void testAuthenticate_userDisabled() {
         // 准备参数
         String username = randomString();
         String password = randomString();
@@ -129,7 +129,7 @@ public class AuthServiceImplTest extends BaseDbUnitTest {
         when(userService.isPasswordMatch(eq(password), eq(user.getPassword()))).thenReturn(true);
 
         // 调用, 并断言异常
-        AssertUtils.assertServiceException(() -> authService.login0(username, password),
+        AssertUtils.assertServiceException(() -> authService.authenticate(username, password),
                 AUTH_LOGIN_USER_DISABLED);
         verify(loginLogService).createLoginLog(
                 argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType())