Ver Fonte

用户认证功能

reghao há 5 anos atrás
pai
commit
d722e227c5
35 ficheiros alterados com 511 adições e 261 exclusões
  1. 5 0
      dagent/src/main/java/cn/reghao/autodop/dagent/kvm/KvmManager.java
  2. 6 0
      dmaster/pom.xml
  3. 12 43
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/cache/OrchestrationCache.java
  4. 0 45
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/caching/DeployCaching.java
  5. 2 2
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/controller/AppBuildController.java
  6. 12 4
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/controller/AppManageController.java
  7. 1 2
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/controller/AppOrchestrateController.java
  8. 4 2
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/entity/orchestration/AppOrchestration.java
  9. 3 0
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/repository/deploy/DeployedAppRepository.java
  10. 2 0
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/repository/log/LogRepository.java
  11. 14 11
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/repository/orchestration/AppDAO.java
  12. 3 1
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/repository/orchestration/AppOrchestrationRepository.java
  13. 15 13
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/AppBuildService.java
  14. 3 6
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/AppLogManager.java
  15. 11 8
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/AppStatusManager.java
  16. 3 3
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/build/BuildDispatcher.java
  17. 20 0
      dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/UserService.java
  18. 21 0
      dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/config/AccessDeniedHandlerImpl.java
  19. 0 29
      dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/config/AuthFailureHandlerImpl.java
  20. 0 39
      dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/config/AuthSuccessHandlerImpl.java
  21. 21 0
      dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/config/AuthenticationEntryPointImpl.java
  22. 21 16
      dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/config/WebSecurityConfig.java
  23. 26 5
      dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/controller/IndexController.java
  24. 19 0
      dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/controller/TokenController.java
  25. 35 0
      dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/controller/UserController.java
  26. 107 0
      dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/jwt/JwtToken.java
  27. 44 0
      dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/jwt/JwtTokenFilter.java
  28. 1 1
      dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/jwt/UserDetailsServiceImpl.java
  29. 49 20
      dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/jwt/UsernamePasswordAuthFilter.java
  30. 3 6
      dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/jwt/UsernamePasswordAuthProvider.java
  31. 3 3
      dmaster/src/main/java/cn/reghao/autodop/dmaster/common/config/WebMvcConfig.java
  32. 2 2
      dmaster/src/main/java/cn/reghao/autodop/dmaster/common/exception/ControllerExceptionHandler.java
  33. 40 0
      dmaster/src/main/java/cn/reghao/autodop/dmaster/common/exception/FilterExceptionHandler.java
  34. 1 0
      dmaster/src/main/java/cn/reghao/autodop/dmaster/common/exception/WebErrorController.java
  35. 2 0
      dmaster/src/main/resources/application.yml

+ 5 - 0
dagent/src/main/java/cn/reghao/autodop/dagent/kvm/KvmManager.java

@@ -6,5 +6,10 @@ package cn.reghao.autodop.dagent.kvm;
  */
 public class KvmManager {
     public static void main(String[] args) throws Exception {
+        /*Connect conn = new Connect("qemu:///system", true);
+        Domain testDomain=conn.domainLookupByName("test");
+        System.out.println("Domain:" + testDomain.getName() + " id " +
+                testDomain.getID() + " running " +
+                testDomain.getOSType());*/
     }
 }

+ 6 - 0
dmaster/pom.xml

@@ -117,6 +117,12 @@
             <artifactId>jsch</artifactId>
             <version>0.1.55</version>
         </dependency>
+
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt</artifactId>
+            <version>0.9.1</version>
+        </dependency>
     </dependencies>
 
     <profiles>

+ 12 - 43
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/caching/OrchestrationCaching.java → dmaster/src/main/java/cn/reghao/autodop/dmaster/app/cache/OrchestrationCache.java

@@ -1,4 +1,4 @@
-package cn.reghao.autodop.dmaster.app.caching;
+package cn.reghao.autodop.dmaster.app.cache;
 
 import cn.reghao.autodop.dmaster.app.entity.orchestration.AppOrchestration;
 import cn.reghao.autodop.dmaster.app.entity.orchestration.ProjOrchestration;
@@ -9,17 +9,17 @@ import cn.reghao.autodop.dmaster.app.repository.build.AppUpdateRepository;
 import cn.reghao.autodop.dmaster.app.repository.orchestration.AppOrchestrationRepository;
 import cn.reghao.autodop.dmaster.app.repository.orchestration.NotificationRepository;
 import cn.reghao.autodop.dmaster.app.repository.orchestration.ProjectOrchestrationRepository;
-import org.springframework.cache.annotation.CacheEvict;
-import org.springframework.cache.annotation.CachePut;
 import org.springframework.cache.annotation.Cacheable;
 import org.springframework.stereotype.Service;
 
 /**
+ * 应用编排缓存
+ *
  * @author reghao
  * @date 2020-03-06 15:17:33
  */
 @Service
-public class OrchestrationCaching {
+public class OrchestrationCache {
     private ProjectOrchestrationRepository projRepository;
     private AppOrchestrationRepository appRepository;
     private AppUpdateRepository appUpdateRepository;
@@ -28,13 +28,13 @@ public class OrchestrationCaching {
     private NotificationRepository notificationRepository;
     private ProjDAO projDAO;
 
-    public OrchestrationCaching(ProjectOrchestrationRepository projRepository,
-                                AppOrchestrationRepository appRepository,
-                                AppUpdateRepository appUpdateRepository,
-                                AppCompileRepository appCompileRepository,
-                                AppPackRepository appPackRepository,
-                                NotificationRepository notificationRepository,
-                                ProjDAO projDAO) {
+    public OrchestrationCache(ProjectOrchestrationRepository projRepository,
+                              AppOrchestrationRepository appRepository,
+                              AppUpdateRepository appUpdateRepository,
+                              AppCompileRepository appCompileRepository,
+                              AppPackRepository appPackRepository,
+                              NotificationRepository notificationRepository,
+                              ProjDAO projDAO) {
         this.projRepository = projRepository;
         this.appRepository = appRepository;
         this.appUpdateRepository = appUpdateRepository;
@@ -44,40 +44,9 @@ public class OrchestrationCaching {
         this.projDAO = projDAO;
     }
 
-    @Cacheable(cacheNames = "proj", key = "#proj.projId")
-    public void addProj(ProjOrchestration proj) {
-    }
-
-    @Cacheable(cacheNames = "app", key = "#app.appId")
-    public void addApp(AppOrchestration app) {
-    }
-
-    @Cacheable(cacheNames = "proj", key = "#projId")
-    public ProjOrchestration findByProjId(String projId) {
-        // TODO 数据库中没有数据时不缓存
-        ProjOrchestration proj = projRepository.findByProjId(projId);
-        return proj;
-    }
-
-    @Cacheable(cacheNames = "app", key = "#appId")
+    // TODO @Cacheable(cacheNames = "app", key = "#appId")
     public AppOrchestration findByAppId(String appId) {
         AppOrchestration app = appRepository.findByAppId(appId);
         return app;
     }
-
-    @CachePut(cacheNames = "proj", key = "#proj.projId")
-    public void modifyProj(ProjOrchestration proj) {
-    }
-
-    @CachePut(cacheNames = "app", key = "#app.appId")
-    public void modifyApp(AppOrchestration app) {
-    }
-
-    @CacheEvict(cacheNames = "proj", key = "#projId")
-    public void deleteProj(String projId) {
-    }
-
-    @CacheEvict(cacheNames = "app", key = "#appId")
-    public void deleteApp(String appId) {
-    }
 }

+ 0 - 45
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/caching/DeployCaching.java

@@ -1,45 +0,0 @@
-package cn.reghao.autodop.dmaster.app.caching;
-
-import cn.reghao.autodop.dmaster.app.entity.deploy.DeployedApp;
-import cn.reghao.autodop.dmaster.app.entity.orchestration.AppOrchestration;
-import cn.reghao.autodop.dmaster.app.repository.deploy.DeployedAppRepository;
-import org.springframework.cache.annotation.Cacheable;
-import org.springframework.stereotype.Service;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * @author reghao
- * @date 2020-05-20 22:23:44
- */
-@Service
-public class DeployCaching {
-    private DeployedAppRepository deployedAppRepository;
-
-    public DeployCaching(DeployedAppRepository deployedAppRepository) {
-        this.deployedAppRepository = deployedAppRepository;
-    }
-
-    /*@Cacheable(cacheNames = "deployedApp", key = "#appId")
-    public boolean isAppDeployed(String appId) {
-        DeployedApp deployedApp = deployedAppRepository.findByAppId(appId);
-        return deployedApp != null;
-    }*/
-
-    @Cacheable(cacheNames = "deployedApp", key = "#appId", unless = "#result != null")
-    public DeployedApp isAppDeployed(AppOrchestration app) {
-        return deployedAppRepository.findByApp(app);
-    }
-
-    @Cacheable(cacheNames = "deployedApp", unless = "#result != null")
-    public List<String> deployedApps() {
-        /*List<DeployedApp> deployedApps = deployedAppRepository.findAll();
-        return deployedApps.stream()
-                .map(deployedApp -> deployedApp.getAppId())
-                .collect(Collectors.toList());*/
-
-        return new ArrayList<>();
-    }
-}

+ 2 - 2
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/controller/AppBuildController.java

@@ -126,12 +126,12 @@ public class AppBuildController {
         return new HashSet<>(Arrays.asList(array));
     }
 
-    @ApiOperation(value = "需要构建部署的应用")
+    @ApiOperation(value = "需要构建的应用")
     @GetMapping("/list")
     public ResponseEntity<String> buildList(@RequestParam("env") String env,
                                             @RequestParam("page") int page,
                                             @RequestParam("size") int size) {
-        PageRequest pageRequest = PageRequest.of(page-1, size);
+        PageRequest pageRequest = PageRequest.of(page-1, size, Sort.by(Sort.Direction.DESC, "updateTime"));
         PageList<AppToBuild> pageList = buildService.buildList(env, pageRequest);
         return ResponseEntity.ok().body(WebResult.success(pageList));
     }

+ 12 - 4
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/controller/AppManageController.java

@@ -2,6 +2,8 @@ package cn.reghao.autodop.dmaster.app.controller;
 
 import cn.reghao.autodop.common.deploy.AppStatus;
 import cn.reghao.autodop.common.dockerc.exception.DockerException;
+import cn.reghao.autodop.dmaster.app.entity.constant.BuildDeployEnv;
+import cn.reghao.autodop.dmaster.app.repository.deploy.DeployedAppRepository;
 import cn.reghao.autodop.dmaster.app.service.AppLogManager;
 import cn.reghao.autodop.dmaster.app.service.AppStatusManager;
 import cn.reghao.autodop.dmaster.app.vo.LogFile;
@@ -10,6 +12,8 @@ import cn.reghao.autodop.dmaster.common.webresult.WebResult;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Sort;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
 
@@ -55,13 +59,17 @@ public class AppManageController {
 
     @ApiOperation(value = "获取所有已部署应用的运行状态")
     @GetMapping("/status")
-    public ResponseEntity<String> status(/*@RequestParam("env") String env*/) throws DockerException {
-        //String env1 = BuildDeployEnv.valueOf(env).name();
-        List<AppStatus> statusList = statusManager.status("dev");
+    public ResponseEntity<String> status(@RequestParam("env") String env,
+                                         @RequestParam("page") int page,
+                                         @RequestParam("size") int size) throws DockerException {
+        String env1 = BuildDeployEnv.valueOf(env).name();
+        PageRequest pageRequest =
+                PageRequest.of(page-1, size, Sort.by(Sort.Direction.DESC, "updateTime"));
+        List<AppStatus> statusList = statusManager.status(env1, pageRequest);
+
         PageList<AppStatus> pageList = new PageList<>();
         pageList.setList(statusList);
         pageList.setTotalSize(statusList.size());
-
         return ResponseEntity.ok().body(WebResult.success(pageList));
     }
 

+ 1 - 2
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/controller/AppOrchestrateController.java

@@ -101,8 +101,7 @@ public class AppOrchestrateController {
     @ApiOperation(value = "修改项目/应用编排")
     @PutMapping("/{type}")
     public ResponseEntity<String> modifyOrchestration(@PathVariable("type") int type, @RequestBody String json) {
-
-
+        // TODO 修改仓库相关的字段时应该删除本地仓库
         boolean res = appOrchestrateService.modify(type, json);
         if (res) {
             return ResponseEntity.ok().body(WebResult.success("ok"));

+ 4 - 2
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/entity/orchestration/AppOrchestration.java

@@ -33,8 +33,6 @@ public class AppOrchestration extends BaseEntity implements Cloneable {
     private boolean alwaysBuild;
     // 编译 app 时所处的目录,以仓库目录为起点
     private String compileDir;
-    // TODO 添加定时构建部署选项
-    // TODO 接入到项目管理系统
     // 配置文件
     @ElementCollection(fetch = FetchType.EAGER)
     private Set<ConfigFile> configFiles;
@@ -56,6 +54,10 @@ public class AppOrchestration extends BaseEntity implements Cloneable {
     // 是否启用编排
     @Column(nullable = false)
     private boolean enable;
+    // TODO 添加一个 role 字段,表示哪些权限的用户可以访问
+    // TODO 添加一个 delete 字段,表示是否被删除。只做逻辑上的删除
+    // TODO 添加定时构建部署选项
+    // TODO 接入到项目管理系统
 
     @Override
     public Object clone() throws CloneNotSupportedException {

+ 3 - 0
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/repository/deploy/DeployedAppRepository.java

@@ -2,6 +2,8 @@ package cn.reghao.autodop.dmaster.app.repository.deploy;
 
 import cn.reghao.autodop.dmaster.app.entity.deploy.DeployedApp;
 import cn.reghao.autodop.dmaster.app.entity.orchestration.AppOrchestration;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
 import org.springframework.data.jpa.repository.JpaRepository;
 
 /**
@@ -10,4 +12,5 @@ import org.springframework.data.jpa.repository.JpaRepository;
  */
 public interface DeployedAppRepository extends JpaRepository<DeployedApp, Long> {
     DeployedApp findByApp(AppOrchestration app);
+    Page<DeployedApp> findByAppEnv(String env, Pageable pageable);
 }

+ 2 - 0
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/repository/log/LogRepository.java

@@ -14,6 +14,8 @@ import java.time.LocalDateTime;
 import java.util.*;
 
 /**
+ * 持久化构建、部署日志
+ *
  * @author reghao
  * @date 2020-05-26 17:35:26
  */

+ 14 - 11
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/repository/orchestration/AppDAO.java

@@ -25,33 +25,36 @@ public class AppDAO {
             // 实际执行 cross join
             String hql = "select app.appId,app.env,log.commitLog.commitId,log.msg " +
                     "from AppOrchestration app,BuildLog log " +
-                    "where app.env=:env and (log.app = app or app.enable=:enable)  " +
-                    "group by app.appId";
+                    "where app.env=:env and log.app = app and app.enable=:enable and log.id in " +
+                    "(select max(id) from BuildLog log1 group by log1.app.id) " +
+                    "order by log.updateTime desc";
 
             Query hqlQuery = session.createQuery(hql)
                     .setParameter("enable", true)
                     .setParameter("env", env);
 
-            int page = 1;
-            int size = 10;
-            int index = 0;
-            hqlQuery.setFirstResult(index).setMaxResults(size).getResultList();
-            return hqlQuery.getResultList();
+            // TODO 不连续的 id 值
+            /*int index = (page-1)*size;
+            return hqlQuery.setFirstResult(index).setMaxResults(size).getResultList();*/
+            // TODO 后期分页获取
+            List list = hqlQuery.getResultList();
+            return list;
         }
     }
 
     public List<DeployedApp> findDeployedApps(String env) {
         try (Session session = (Session) em.getDelegate()) {
-            // 实际执行 cross join
-            String hql = "select deployed from DeployedApp deployed " +
+            String hql = "select app.appId,deployed.commitId from DeployedApp deployed " +
                     "inner join AppOrchestration app " +
                     "on deployed.app=app " +
-                    "where app.env=:env ";
+                    "where app.env=:env " +
+                    "order by deployed.updateTime desc";
 
             Query hqlQuery = session.createQuery(hql)
                     .setParameter("env", env);
 
-            return hqlQuery.getResultList();
+            List list = hqlQuery.getResultList();
+            return list;
         }
     }
 }

+ 3 - 1
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/repository/orchestration/AppOrchestrationRepository.java

@@ -7,6 +7,7 @@ import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.Modifying;
 
 import javax.transaction.Transactional;
+import java.util.List;
 
 /**
  *
@@ -15,7 +16,8 @@ import javax.transaction.Transactional;
  */
 public interface AppOrchestrationRepository extends JpaRepository<AppOrchestration, Long> {
     AppOrchestration findByAppId(String appId);
-    Page<AppOrchestration> findAllByEnableIsTrue(String env, Pageable pageable);
+    List<AppOrchestration> findAllByEnableIsTrue();
+    Page<AppOrchestration> findAllByEnableIsTrueAndEnv(String env, Pageable pageable);
     Page<AppOrchestration> findByEnv(String env, Pageable pageable);
 
     @Modifying

+ 15 - 13
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/AppBuildService.java

@@ -44,26 +44,28 @@ public class AppBuildService {
 
     public PageList<AppToBuild> buildList(String env, PageRequest pageRequest) {
         PageList<AppToBuild> pageList = new PageList<>();
-
-        /*Page<AppOrchestration> apps = appRepository.findAllByEnableIsTrue(env, pageRequest);
+        Page<AppOrchestration> apps = appRepository.findAllByEnableIsTrueAndEnv(env, pageRequest);
+        pageList.setTotalSize(apps.getTotalElements());
+        pageList.setTotalPages(apps.getTotalPages());
         Set<String> appIds = apps.stream()
-                .filter(app -> app.getEnv().equals(env))
                 .map(AppOrchestration::getAppId)
-                .collect(Collectors.toSet());*/
+                .collect(Collectors.toSet());
 
-        List list = appDAO.findBuildApps(env);
         List<AppToBuild> appToBuilds = new ArrayList<>();
-        /*list.forEach(object -> {
-            Object[] objects = (Object[]) object;
-            appIds.remove(String.valueOf(objects[0]));
-            appToBuilds.add(new AppToBuild(String.valueOf(objects[0]), String.valueOf(objects[1]),
-                    String.valueOf(objects[2]), String.valueOf(objects[3])));
+        // TODO appRepository 和 appDAO 使用的同一个 session,appDAO 显式关闭 session 后前者无法再使用
+        List list = appDAO.findBuildApps(env);
+        list.forEach(ele -> {
+            Object[] objects = (Object[]) ele;
+            if (appIds.contains(String.valueOf(objects[0]))) {
+                appToBuilds.add(new AppToBuild(String.valueOf(objects[0]), String.valueOf(objects[1]),
+                        String.valueOf(objects[2]), String.valueOf(objects[3])));
+                appIds.remove(String.valueOf(objects[0]));
+            }
         });
-
         appIds.forEach(appId -> {
             appToBuilds.add(new AppToBuild(appId, env));
-        });*/
-
+        });
+        pageList.setList(appToBuilds);
         return pageList;
     }
 

+ 3 - 6
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/AppLogManager.java

@@ -2,8 +2,7 @@ package cn.reghao.autodop.dmaster.app.service;
 
 import cn.reghao.autodop.common.grpc.client.GrpcClientProxy;
 import cn.reghao.autodop.common.grpc.facade.app.AppLogService;
-import cn.reghao.autodop.dmaster.app.caching.DeployCaching;
-import cn.reghao.autodop.dmaster.app.caching.OrchestrationCaching;
+import cn.reghao.autodop.dmaster.app.cache.OrchestrationCache;
 import cn.reghao.autodop.dmaster.app.entity.deploy.AppDeploy;
 import cn.reghao.autodop.dmaster.app.entity.deploy.AppLog;
 import cn.reghao.autodop.dmaster.app.entity.orchestration.AppOrchestration;
@@ -21,12 +20,10 @@ import java.util.*;
 @Service
 public class AppLogManager {
     private final int GRPC_PORT = 4001;
-    private OrchestrationCaching caching;
-    private DeployCaching deployCaching;
+    private OrchestrationCache caching;
 
-    public AppLogManager(OrchestrationCaching caching, DeployCaching deployCaching) {
+    public AppLogManager(OrchestrationCache caching) {
         this.caching = caching;
-        this.deployCaching = deployCaching;
     }
 
     public List<LogFile> logFiles(String appId, String host) throws Exception {

+ 11 - 8
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/AppStatusManager.java

@@ -4,11 +4,14 @@ import cn.reghao.autodop.common.deploy.AppStatus;
 import cn.reghao.autodop.common.dockerc.exception.DockerException;
 import cn.reghao.autodop.common.grpc.client.GrpcClientProxy;
 import cn.reghao.autodop.common.grpc.facade.app.AppStatusService;
-import cn.reghao.autodop.dmaster.app.caching.OrchestrationCaching;
+import cn.reghao.autodop.dmaster.app.cache.OrchestrationCache;
 import cn.reghao.autodop.dmaster.app.entity.deploy.DeployedApp;
 import cn.reghao.autodop.dmaster.app.entity.orchestration.AppOrchestration;
+import cn.reghao.autodop.dmaster.app.repository.deploy.DeployedAppRepository;
 import cn.reghao.autodop.dmaster.app.repository.orchestration.AppDAO;
 import com.alibaba.fastjson.JSONObject;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
 import org.springframework.stereotype.Service;
 
 import java.util.ArrayList;
@@ -22,13 +25,13 @@ import java.util.List;
  */
 @Service
 public class AppStatusManager {
+    private DeployedAppRepository deployedRepository;
     private final int GRPC_PORT = 4001;
-    private OrchestrationCaching caching;
-    private AppDAO appDAO;
+    private OrchestrationCache caching;
 
-    public AppStatusManager(OrchestrationCaching caching, AppDAO appDAO) {
+    public AppStatusManager(OrchestrationCache caching, DeployedAppRepository deployedRepository) {
+        this.deployedRepository = deployedRepository;
         this.caching = caching;
-        this.appDAO = appDAO;
     }
 
     public void run(String appId, String commitId) throws DockerException {
@@ -71,12 +74,12 @@ public class AppStatusManager {
         }
     }
 
-    public List<AppStatus> status(String env) throws DockerException {
+    public List<AppStatus> status(String env, PageRequest pageRequest) {
+        Page<DeployedApp> page = deployedRepository.findByAppEnv(env, pageRequest);
         List<AppStatus> appStatusList = new ArrayList<>();
-        List<DeployedApp> deployedApps = appDAO.findDeployedApps(env);
         // TODO 异步处理
         try {
-            for (DeployedApp deployedApp : deployedApps) {
+            for (DeployedApp deployedApp : page.getContent()) {
                 for (String host : deployedApp.getApp().getAppDeploy().getHosts()) {
                     AppStatusService appStatusService = (AppStatusService) new GrpcClientProxy<AppStatusService>()
                             .getProxy(host, GRPC_PORT, AppStatusService.class);

+ 3 - 3
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/build/BuildDispatcher.java

@@ -1,6 +1,6 @@
 package cn.reghao.autodop.dmaster.app.service.build;
 
-import cn.reghao.autodop.dmaster.app.caching.OrchestrationCaching;
+import cn.reghao.autodop.dmaster.app.cache.OrchestrationCache;
 import cn.reghao.autodop.dmaster.app.entity.log.BuildDeployLog;
 import cn.reghao.autodop.dmaster.app.entity.orchestration.AppOrchestration;
 import cn.reghao.autodop.dmaster.app.entity.orchestration.ProjOrchestration;
@@ -24,11 +24,11 @@ import java.util.concurrent.*;
 public class BuildDispatcher {
     // TODO 多线程访问的集合
     private Set<String> buildingApps;
-    private OrchestrationCaching caching;
+    private OrchestrationCache caching;
     private LogConsumer logConsumer;
     private ExecutorService threadPool;
 
-    public BuildDispatcher(OrchestrationCaching caching, LogRepository logDAO) {
+    public BuildDispatcher(OrchestrationCache caching, LogRepository logDAO) {
         this.buildingApps = new HashSet<>();
         this.caching = caching;
         this.logConsumer = new LogConsumer(logDAO);

+ 20 - 0
dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/UserService.java

@@ -0,0 +1,20 @@
+package cn.reghao.autodop.dmaster.auth;
+
+import cn.reghao.autodop.dmaster.auth.repository.UserAuthRepository;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author reghao
+ * @date 2020-06-19 16:36:53
+ */
+@Service
+public class UserService {
+    private UserAuthRepository authRepository;
+
+    public UserService(UserAuthRepository authRepository) {
+        this.authRepository = authRepository;
+    }
+
+    public void createUser() {
+    }
+}

+ 21 - 0
dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/config/AccessDeniedHandlerImpl.java

@@ -0,0 +1,21 @@
+package cn.reghao.autodop.dmaster.auth.config;
+
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.web.access.AccessDeniedHandler;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * @author reghao
+ * @date 2020-06-19 13:47:38
+ */
+public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
+    @Override
+    public void handle(HttpServletRequest request, HttpServletResponse response,
+                       AccessDeniedException accessDeniedException) throws IOException, ServletException {
+        response.getWriter().println(accessDeniedException.getMessage());
+    }
+}

+ 0 - 29
dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/config/AuthFailureHandlerImpl.java

@@ -1,29 +0,0 @@
-package cn.reghao.autodop.dmaster.auth.config;
-
-import org.springframework.http.HttpStatus;
-import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.web.authentication.AuthenticationFailureHandler;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-
-/**
- * 认证失败后的处理
- *
- * @author reghao
- * @date 2019-04-09 00:02:34
- */
-public class AuthFailureHandlerImpl implements AuthenticationFailureHandler {
-    @Override
-    public void onAuthenticationFailure(HttpServletRequest request,
-                                        HttpServletResponse response,
-                                        AuthenticationException exception)
-            throws IOException, ServletException {
-
-        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
-        response.setContentType("text/html;charset=utf-8");
-        response.getWriter().write(exception.getMessage());
-    }
-}

+ 0 - 39
dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/config/AuthSuccessHandlerImpl.java

@@ -1,39 +0,0 @@
-package cn.reghao.autodop.dmaster.auth.config;
-
-import org.springframework.security.core.Authentication;
-import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
-import org.springframework.security.web.savedrequest.SavedRequest;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-
-/**
- * 认证成功后跳转到登录前的地址
- *
- * @author reghao
- * @date 2019-04-08 23:50:51
- */
-public class AuthSuccessHandlerImpl implements AuthenticationSuccessHandler {
-    @Override
-    public void onAuthenticationSuccess(HttpServletRequest request,
-                                        HttpServletResponse response,
-                                        Authentication authentication)
-            throws IOException, ServletException {
-        String body = "";
-        response.getOutputStream().print(body);
-    }
-
-    static class Result {
-        private int code;
-        private ResultData data;
-    }
-
-    static class ResultData {
-        private String msg;
-        private boolean success;
-        private String token;
-        private String user;
-    }
-}

+ 21 - 0
dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/config/AuthenticationEntryPointImpl.java

@@ -0,0 +1,21 @@
+package cn.reghao.autodop.dmaster.auth.config;
+
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * @author reghao
+ * @date 2020-06-19 13:43:59
+ */
+public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {
+    @Override
+    public void commence(HttpServletRequest request, HttpServletResponse response,
+                         AuthenticationException authException) throws IOException, ServletException {
+        response.getWriter().println(authException.getMessage());
+    }
+}

+ 21 - 16
dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/config/WebSecurityConfig.java

@@ -1,7 +1,9 @@
 package cn.reghao.autodop.dmaster.auth.config;
 
-import cn.reghao.autodop.dmaster.auth.impl.formlogin.UserDetailsServiceImpl;
-import cn.reghao.autodop.dmaster.auth.impl.formlogin.UsernamePasswordAuthFilter;
+import cn.reghao.autodop.dmaster.auth.jwt.JwtTokenFilter;
+import cn.reghao.autodop.dmaster.auth.jwt.UserDetailsServiceImpl;
+import cn.reghao.autodop.dmaster.auth.jwt.UsernamePasswordAuthFilter;
+import cn.reghao.autodop.dmaster.auth.jwt.UsernamePasswordAuthProvider;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.security.access.expression.SecurityExpressionHandler;
@@ -24,9 +26,10 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
  */
 @Configuration
 @EnableWebSecurity
-//@EnableGlobalMethodSecurity(prePostEnabled = true)
+@EnableGlobalMethodSecurity(prePostEnabled = true)
 public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
     private UserDetailsServiceImpl userDetailsService;
+    private final String authUrl = "/login";
 
     public WebSecurityConfig(UserDetailsServiceImpl userDetailsService) {
         this.userDetailsService = userDetailsService;
@@ -34,32 +37,35 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 
     @Override
     protected void configure(HttpSecurity http) throws Exception {
+        // TODO 具体的权限验证在 JwtTokenFilter 中完成
         http.authorizeRequests()
                 .expressionHandler(webExpressionHandler())
-                .antMatchers("/api/**").permitAll()
                 .antMatchers("/**").permitAll()
+                //.antMatchers("/*").permitAll()
                 .antMatchers("/actuator/health").permitAll()
                 .anyRequest().authenticated();
 
-        http.exceptionHandling().accessDeniedPage("/deny");
+        // 异常处理
+        /*http.exceptionHandling()
+                // 认证异常
+                .authenticationEntryPoint(new AuthenticationEntryPointImpl())
+                // 访问异常
+                .accessDeniedHandler(new AccessDeniedHandlerImpl());*/
 
         // 禁用 CSRF
         //http.csrf().requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/authorize")).disable();
         http.csrf().disable();
+        //http.cors();
 
         // 基于表单的认证
         http.formLogin()
-                // 登录接口
-                .loginProcessingUrl("/login")
-                .successHandler(new AuthSuccessHandlerImpl())
-                .failureHandler(new AuthFailureHandlerImpl())
-                .and()
-                .logout()
-                //.logoutSuccessUrl("/login")
+                // 认证接口
+                .loginProcessingUrl(authUrl)
                 .and()
                 .httpBasic().disable();
 
         http.addFilterBefore(usernamePasswordAuthFilter(), UsernamePasswordAuthenticationFilter.class);
+        http.addFilterAfter(new JwtTokenFilter(), UsernamePasswordAuthFilter.class);
     }
 
     /**
@@ -72,14 +78,13 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
     @Override
     public void configure(AuthenticationManagerBuilder auth) throws Exception {
         auth.userDetailsService(userDetailsService);
+        // TODO 尝试使用 DaoAuthenticationProvider
+        auth.authenticationProvider(new UsernamePasswordAuthProvider(userDetailsService));
     }
 
     private UsernamePasswordAuthFilter usernamePasswordAuthFilter() throws Exception {
-        UsernamePasswordAuthFilter filter = new UsernamePasswordAuthFilter("/login", "POST");
+        UsernamePasswordAuthFilter filter = new UsernamePasswordAuthFilter(authUrl, "POST");
         filter.setAuthenticationManager(super.authenticationManager());
-        filter.setAuthenticationSuccessHandler(new AuthSuccessHandlerImpl());
-        filter.setAuthenticationFailureHandler(new AuthFailureHandlerImpl());
-
         return filter;
     }
 

+ 26 - 5
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/controller/IndexController.java → dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/controller/IndexController.java

@@ -1,4 +1,4 @@
-package cn.reghao.autodop.dmaster.app.controller;
+package cn.reghao.autodop.dmaster.auth.controller;
 
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
@@ -19,20 +19,41 @@ import java.util.Map;
 @Slf4j
 @Api(tags = "测试接口")
 @RestController
+//@RequestMapping("/admin")
 public class IndexController {
     @ApiOperation(value = "获取用户信息")
     @ApiImplicitParams(
             @ApiImplicitParam(name="appId", value="应用 ID", paramType="path", dataType = "String")
     )
-    @GetMapping("/admin/getInfo")
+    @GetMapping("/api/getInfo")
     public ResponseEntity<String> adminInfo() {
         String result = "{\"code\":0,\"data\":{\"name\":\"admin\",\"roles\":[\"Home\",\"Dashbord\",\"Driver\",\"Driver-index\",\"Permission\",\"PageUser\",\"PageAdmin\",\"Roles\",\"Table\",\"BaseTable\",\"ComplexTable\",\"Icons\",\"Icons-index\",\"Components\",\"Sldie-yz\",\"Upload\",\"Carousel\",\"Echarts\",\"Sldie-chart\",\"Dynamic-chart\",\"Map-chart\",\"Excel\",\"Excel-out\",\"Excel-in\",\"Mutiheader-out\",\"Error\",\"Page404\",\"Github\",\"NavTest\",\"Nav1\",\"Nav2\",\"Nav2-1\",\"Nav2-2\",\"Nav2-2-1\",\"Nav2-2-2\",\"*404\"],\"introduce\":\"哈哈哈\"},\"_res\":{\"status\":200}}";
         return ResponseEntity.ok().body(result);
     }
 
-    @PostMapping("/admin/login")
-    public ResponseEntity<String> admin() {
-        return ResponseEntity.ok().body("result");
+    @PostMapping("/login")
+    public ResponseEntity<String> login() {
+        return ResponseEntity.ok().body("");
+    }
+
+    @GetMapping("/api/getCardsData")
+    public ResponseEntity<String> getCardsData() {
+        return ResponseEntity.ok().body("cards data");
+    }
+
+    @GetMapping("/api/getLineData")
+    public ResponseEntity<String> getLineData() {
+        return ResponseEntity.ok().body("line data");
+    }
+
+    @GetMapping("/api/getTableList")
+    public ResponseEntity<String> getTableList() {
+        return ResponseEntity.ok().body("table list");
+    }
+
+    @GetMapping("/api/getBarData")
+    public ResponseEntity<String> getBarData() {
+        return ResponseEntity.ok().body("bar data");
     }
 
     @Data

+ 19 - 0
dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/controller/TokenController.java

@@ -0,0 +1,19 @@
+package cn.reghao.autodop.dmaster.auth.controller;
+
+import io.swagger.annotations.Api;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * @author reghao
+ * @date 2020-02-28 11:33:23
+ */
+@Api(tags = "令牌接口")
+@RestController
+@RequestMapping("/token")
+public class TokenController {
+    @GetMapping("/refresh")
+    public ResponseEntity<String> refreshToken() {
+        return ResponseEntity.ok().body("new token");
+    }
+}

+ 35 - 0
dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/controller/UserController.java

@@ -0,0 +1,35 @@
+package cn.reghao.autodop.dmaster.auth.controller;
+
+import cn.reghao.autodop.dmaster.auth.UserService;
+import cn.reghao.autodop.dmaster.common.webresult.WebResult;
+import io.swagger.annotations.Api;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.annotation.Secured;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * @author reghao
+ * @date 2020-02-28 11:33:23
+ */
+@Api(tags = "用户接口")
+@RestController
+@RequestMapping("/api/user")
+public class UserController {
+    private UserService userService;
+
+    public UserController(UserService userService) {
+        this.userService = userService;
+    }
+
+    // TODO 指定角色的用户才能访问
+    @Secured("ROLE_ADMIN")
+    @PostMapping(consumes = "application/json")
+    public ResponseEntity<String> createUser(@RequestBody String json) throws Exception {
+        return ResponseEntity.ok().body(WebResult.success("ok"));
+    }
+
+    @GetMapping
+    public ResponseEntity<String> getUserByPage(@RequestParam("page") int page, @RequestParam("size") int size) {
+        return ResponseEntity.ok().body("");
+    }
+}

+ 107 - 0
dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/jwt/JwtToken.java

@@ -0,0 +1,107 @@
+package cn.reghao.autodop.dmaster.auth.jwt;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.ExpiredJwtException;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.AuthorityUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * JWT 令牌服务
+ * TODO 将 JWT 令牌存放在 redis 中
+ *
+ * @author reghao
+ * @date 2019-11-17 23:10:58
+ */
+@Slf4j
+public class JwtToken {
+    // 10 mins
+    private static final long EXPIRATION_TIME = 60_000*60*24*7;
+    // TODO key 需要动态变化
+    private static final String KEY = "Reghao";
+    private static final String TOKEN_PREFIX = "Bearer ";
+    private static final String HEADER_STRING = "Authorization";
+
+    /**
+     * 生成一个新 token
+     *
+     * @param
+     * @return
+     * @date 2019-11-21 下午4:39
+     */
+    public static String newToken(String username) {
+        String jwt = Jwts.builder()
+                .claim("authorities", "ROLE_USER")
+                .setSubject(username)
+                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
+                .signWith(SignatureAlgorithm.HS256, KEY)
+                .compact();
+
+        return jwt;
+    }
+
+    /**
+     * TODO 检查 token 是否有效
+     *
+     * @param
+     * @return
+     * @date 2019-11-21 下午4:39
+     */
+    public static boolean isValid(String token) {
+        try {
+            Claims claims = Jwts.parser()
+                    .setSigningKey(KEY)
+                    .parseClaimsJws(token)
+                    .getBody();
+            return true;
+        } catch (ExpiredJwtException e) {
+            log.warn("令牌过期...");
+            return false;
+        }
+    }
+
+    public static void setAuthentication(HttpServletResponse response, String username) throws IOException {
+        String jwt = Jwts.builder()
+                .claim("authorities", "ROLE_USER")
+                .setSubject(username)
+                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
+                .signWith(SignatureAlgorithm.HS256, KEY)
+                .compact();
+
+        response.setContentType("application/json");
+        response.setStatus(HttpServletResponse.SC_OK);
+        // 由于没有托管在 Spring MVC 中,因此需要单独处理跨域
+        response.addHeader("Access-Control-Allow-Origin", "*");
+        response.addHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS,PUT,DELETE");
+        response.setHeader("Access-Control-Allow-Headers", "x-requested-with,Authorization,Content-Type");
+        response.getOutputStream().print(jwt);
+    }
+
+    static Authentication getAuthentication(HttpServletRequest request) {
+        String token = request.getHeader(HEADER_STRING);
+        if (token != null) {
+            Claims claims = Jwts.parser()
+                    .setSigningKey(KEY)
+                    .parseClaimsJws(token)
+                    //.parseClaimsJws(token.replace(TOKEN_PREFIX, ""))
+                    .getBody();
+
+            String user = claims.getSubject();
+            List<GrantedAuthority> authorities =
+                    AuthorityUtils.commaSeparatedStringToAuthorityList((String) claims.get("authorities"));
+            return user != null ? new UsernamePasswordAuthenticationToken(user, null, authorities) : null;
+        }
+
+        return null;
+    }
+}

+ 44 - 0
dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/jwt/JwtTokenFilter.java

@@ -0,0 +1,44 @@
+package cn.reghao.autodop.dmaster.auth.jwt;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * 验证请求是否携带 JWT token,每个请求都会被验证
+ *
+ * @author reghao
+ * @date 2019-11-18 10:00:22
+ */
+public class JwtTokenFilter extends OncePerRequestFilter {
+    @Override
+    protected void doFilterInternal(HttpServletRequest request,
+                                    HttpServletResponse response,
+                                    FilterChain chain) throws ServletException, IOException {
+        String uri = request.getRequestURI();
+        String method = request.getMethod();
+        // TODO 不处理 OPTIONS 请求和非 /api 开头的请求
+        if ("OPTIONS".equals(method) || !uri.startsWith("/api")) {
+            chain.doFilter(request, response);
+            return;
+        }
+
+        String token = request.getHeader("Authorization");
+        if (token != null) {
+            if (JwtToken.isValid(token)) {
+                Authentication authentication = JwtToken.getAuthentication(request);
+                SecurityContextHolder.getContext().setAuthentication(authentication);
+            } else {
+                response.sendError(HttpServletResponse.SC_FORBIDDEN, "令牌已过期");
+            }
+        } else {
+            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "尚未认证,没有令牌");
+        }
+        chain.doFilter(request, response);
+    }
+}

+ 1 - 1
dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/impl/formlogin/UserDetailsServiceImpl.java → dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/jwt/UserDetailsServiceImpl.java

@@ -1,4 +1,4 @@
-package cn.reghao.autodop.dmaster.auth.impl.formlogin;
+package cn.reghao.autodop.dmaster.auth.jwt;
 
 import cn.reghao.autodop.dmaster.auth.entity.UserAuth;
 import cn.reghao.autodop.dmaster.auth.repository.RoleRepository;

+ 49 - 20
dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/impl/formlogin/UsernamePasswordAuthFilter.java → dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/jwt/UsernamePasswordAuthFilter.java

@@ -1,37 +1,39 @@
-package cn.reghao.autodop.dmaster.auth.impl.formlogin;
+package cn.reghao.autodop.dmaster.auth.jwt;
 
+import cn.reghao.autodop.common.utils.JsonUtil;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
 import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
 
+import javax.servlet.FilterChain;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.BufferedReader;
 import java.io.IOException;
+import java.io.PrintWriter;
 
 /**
- * 替换 UsernamePasswordAuthenticationFilter
+ * 替换 UsernamePasswordAuthenticationFilter,用于认证用户。匹配指定 URL 才会进行处理
  *
  * @author reghao
  * @date 2019-11-18 08:55:59
  */
+@Slf4j
 public class UsernamePasswordAuthFilter extends AbstractAuthenticationProcessingFilter {
-    private String httpMethod;
-
     public UsernamePasswordAuthFilter(String authUrl, String httpMethod) {
         super(new AntPathRequestMatcher(authUrl, httpMethod));
-        this.httpMethod = httpMethod;
     }
 
     @Override
     public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
             throws AuthenticationException, IOException, ServletException {
-
         // form-data 中的 username 和 password 参数
         String username = request.getParameter("user");
         String password = request.getParameter("password");
@@ -53,31 +55,44 @@ public class UsernamePasswordAuthFilter extends AbstractAuthenticationProcessing
      * @return
      * @date 2019-11-18 上午11:15
      */
-    /*@Override
+    @Override
     protected void successfulAuthentication(HttpServletRequest request,
                                             HttpServletResponse response,
                                             FilterChain chain,
                                             Authentication auth) throws IOException, ServletException {
+        // TODO 将 username:token 存储在缓存中,用户注销时,在缓存中将 token 置为不可用
+        String accessToken = JwtToken.newToken(auth.getName());
+        ResultData resultData = new ResultData();
+        resultData.setMsg("登录成功");
+        resultData.setSuccess(true);
+        resultData.setToken(accessToken);
+        resultData.setUser(auth.getName());
+        Result result = new Result();
+        result.setCode(0);
+        result.setData(resultData);
 
-        SavedRequest savedRequest = (SavedRequest) request.getSession().getAttribute("SPRING_SECURITY_SAVED_REQUEST");
-        if (savedRequest != null) {
-            String redirectUrl = savedRequest.getRedirectUrl();
-            // 跳转到登录前
-            response.sendRedirect(redirectUrl);
-        } else {
-            JwtTokenProvider.setAuthentication(response, auth.getName());
-        }
-    }*/
+        response.setHeader("Authorization", "Bearer " + accessToken);
+        response.setContentType("text/html; charset=utf-8");
+
+        // 由于没有托管在 Spring MVC 中,因此需要单独处理跨域
+        response.addHeader("Access-Control-Allow-Origin", "*");
+        response.addHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS,PUT,DELETE");
+        response.setHeader("Access-Control-Allow-Headers", "x-requested-with,Authorization,Content-Type");
+
+        PrintWriter pt = response.getWriter();
+        log.info("认证成功并返回");
+        pt.println(JsonUtil.objectToJson(result));
+    }
 
-    /*@Override
+    @Override
     protected void unsuccessfulAuthentication(HttpServletRequest request,
                                               HttpServletResponse response,
                                               AuthenticationException failed) throws IOException, ServletException {
 
         response.setContentType("application/json");
-        response.setStatus(HttpServletResponse.SC_OK);
-        response.getOutputStream().println("Internal Server Error");
-    }*/
+        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+        response.getOutputStream().println("username or password invalid");
+    }
 
     private JsonObject getBody(HttpServletRequest request) throws IOException {
         BufferedReader br = request.getReader();
@@ -89,4 +104,18 @@ public class UsernamePasswordAuthFilter extends AbstractAuthenticationProcessing
 
         return new JsonParser().parse(sb.toString()).getAsJsonObject();
     }
+
+    @Data
+    class Result {
+        private int code;
+        private ResultData data;
+    }
+
+    @Data
+    class ResultData {
+        private String msg;
+        private boolean success;
+        private String token;
+        private String user;
+    }
 }

+ 3 - 6
dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/impl/formlogin/UsernamePasswordAuthProvider.java → dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/jwt/UsernamePasswordAuthProvider.java

@@ -1,14 +1,12 @@
-package cn.reghao.autodop.dmaster.auth.impl.formlogin;
+package cn.reghao.autodop.dmaster.auth.jwt;
 
 import cn.reghao.autodop.common.utils.security.Cryptor;
 import cn.reghao.autodop.common.utils.security.Sha256Cryptor;
 import cn.reghao.autodop.dmaster.auth.entity.UserAuth;
 import org.springframework.security.authentication.AuthenticationProvider;
-import org.springframework.security.authentication.DisabledException;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
-import org.springframework.stereotype.Component;
 
 import java.security.NoSuchAlgorithmException;
 
@@ -18,7 +16,6 @@ import java.security.NoSuchAlgorithmException;
  * @author reghao
  * @date 2019-04-09 09:07:40
  */
-@Component
 public class UsernamePasswordAuthProvider implements AuthenticationProvider {
     private UserDetailsServiceImpl userDetailsService;
     private Cryptor cryptor;
@@ -36,10 +33,10 @@ public class UsernamePasswordAuthProvider implements AuthenticationProvider {
 
         // 从数据库中获取用户认证信息
         UserAuth userAuth = (UserAuth) userDetailsService.loadUserByUsername(username);
-        String encodedPassword = cryptor.encrypt(password + userAuth.getSalt());
+        /*String encodedPassword = cryptor.encrypt(password + userAuth.getSalt());
         if (!userAuth.getPassword().equals(encodedPassword)) {
             throw new DisabledException("用户名/密码错误");
-        }
+        }*/
 
         return new UsernamePasswordAuthenticationToken(userAuth, password, userAuth.getAuthorities());
     }

+ 3 - 3
dmaster/src/main/java/cn/reghao/autodop/dmaster/common/config/WebMvcConfig.java

@@ -75,9 +75,9 @@ public class WebMvcConfig implements WebMvcConfigurer {
         // 定义了一个 CorsConfiguration 对象
         registry.addMapping("/**")
                 .allowedOrigins("*")
-                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                 .allowedHeaders("*")
-                .maxAge(3600)
-                .allowCredentials(true);
+                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
+                .allowCredentials(true)
+                .maxAge(3600);
     }
 }

+ 2 - 2
dmaster/src/main/java/cn/reghao/autodop/dmaster/common/exception/GlobalExceptionHandler.java → dmaster/src/main/java/cn/reghao/autodop/dmaster/common/exception/ControllerExceptionHandler.java

@@ -9,7 +9,7 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.ResponseBody;
 
 /**
- * 全局异常处理类,处理业务层抛出的异常
+ * 全局异常处理类,处理 controller 抛出的异常
  *
  * @author reghao
  * @date 2019/03/21 10:25:49
@@ -17,7 +17,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
 @Slf4j
 @ControllerAdvice
 @ResponseBody
-public class GlobalExceptionHandler {
+public class ControllerExceptionHandler {
     /**
      * 处理所有的异常
      *

+ 40 - 0
dmaster/src/main/java/cn/reghao/autodop/dmaster/common/exception/FilterExceptionHandler.java

@@ -0,0 +1,40 @@
+package cn.reghao.autodop.dmaster.common.exception;
+
+import org.springframework.boot.autoconfigure.web.ErrorProperties;
+import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
+import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 处理 filter 中抛出的异常
+ *
+ * @author reghao
+ * @date 2020-06-19 13:34:19
+ */
+@RestController
+public class FilterExceptionHandler extends BasicErrorController {
+    public FilterExceptionHandler() {
+        super(new DefaultErrorAttributes(), new ErrorProperties());
+    }
+
+    @Override
+    @RequestMapping(produces = {MediaType.APPLICATION_JSON_VALUE})
+    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
+        Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
+        HttpStatus status = getStatus(request);
+
+        Map<String,Object> map = new HashMap<>();
+        map.put("code",body.get("status"));
+        map.put("msg",body.get("message"));
+
+        return new ResponseEntity<>(map, HttpStatus.UNAUTHORIZED);
+    }
+}

+ 1 - 0
dmaster/src/main/java/cn/reghao/autodop/dmaster/common/exception/WebErrorController.java

@@ -3,6 +3,7 @@ package cn.reghao.autodop.dmaster.common.exception;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.boot.web.servlet.error.ErrorController;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
 
 import javax.servlet.http.HttpServletRequest;
 

+ 2 - 0
dmaster/src/main/resources/application.yml

@@ -31,6 +31,8 @@ spring:
         hbm2ddl:
           auto: update
         dialect: org.hibernate.dialect.MySQL57Dialect
+  mvc:
+    dispatch-options-request: true
 oss:
   endpoint: http://oss-cn-hangzhou.aliyuncs.com
   key: jYk8lOKwSCorFEz7