Переглянути джерело

1、第三方授权登录

slowslo 3 роки тому
батько
коміт
5ef3285220
70 змінених файлів з 3025 додано та 55 видалено
  1. 1 0
      smart-house-yinchuan/env_files/properties/dev.properties
  2. 6 5
      smart-house-yinchuan/sptg-common/sptg-common-core/src/main/java/com/sptg/common/core/util/aliface/FaceDetectUtil.java
  3. 11 11
      smart-house-yinchuan/sptg-estate/sptg-estate-biz/src/main/java/com/sptg/estate/biz/service/impl/ApplyUserServiceImpl.java
  4. 2 2
      smart-house-yinchuan/sptg-gateway/sptg-app-gateway/src/main/java/com/sptg/gateway/controller/MemberController.java
  5. 28 4
      smart-house-yinchuan/sptg-gateway/sptg-device-gateway/src/main/java/com/sptg/gateway/controller/FileUploadController.java
  6. 32 8
      smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/java/com/sptg/gateway/controller/common/FileManageController.java
  7. 202 0
      smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/java/com/sptg/gateway/controller/permissions/ThirdAuthenticationController.java
  8. 1 0
      smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/ad/ad-material-add.js
  9. 1 0
      smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/device/device-app-package-add.js
  10. 2 0
      smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/estate/car-add.js
  11. 2 0
      smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/estate/car-edit.js
  12. 1 0
      smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/estate/notice-add.js
  13. 2 0
      smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/estate/parking-lot-add.js
  14. 2 0
      smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/estate/parking-lot-edit.js
  15. 2 0
      smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/estate/parking-space-add.js
  16. 2 0
      smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/estate/parking-space-edit.js
  17. 1 0
      smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/estate/repair-add.js
  18. 2 0
      smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/estate/user-add-view.js
  19. 2 0
      smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/estate/user-add.js
  20. 2 0
      smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/estate/user-edit.js
  21. 1 0
      smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/implement/project-detail.js
  22. 1 0
      smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/implement/project-insert.js
  23. 1 0
      smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/permissions/account-add.js
  24. 1 0
      smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/permissions/account-edit.js
  25. 1 0
      smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/permissions/account-setup.js
  26. 0 2
      smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/permissions/password-change.js
  27. 1 0
      smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/util/import-face-zip.js
  28. 10 0
      smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/templates/common/guest-error.html
  29. 6 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-api/pom.xml
  30. 30 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/dto/AccountOauthDto.java
  31. 99 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/entity/AccountOauth.java
  32. 2 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/enums/PermissionsEnum.java
  33. 8 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/feigns/AccountAuthenticationFeign.java
  34. 10 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/feigns/AccountFeign.java
  35. 65 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/feigns/AccountOauthFeign.java
  36. 38 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/feigns/ThirdAuthenticationFeign.java
  37. 5 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/feigns/fallback/AccountAuthenticationFeignFallbackFactory.java
  38. 5 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/feigns/fallback/AccountFeignFallbackFactory.java
  39. 58 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/feigns/fallback/AccountOauthFeignFallbackFactory.java
  40. 47 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/feigns/fallback/ThirdAuthenticationFeignFallbackFactory.java
  41. 94 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/constants/CtwingAuthConstants.java
  42. 30 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/enums/AuthCustomizeSource.java
  43. 109 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/officedemo/CtwingUnifyAccountLoginDemo.java
  44. 216 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/request/AuthCtwingRequest.java
  45. 34 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/util/AuthRequestUtil.java
  46. 51 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/util/ByteFormat.java
  47. 55 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/util/CtwingBase64Utils.java
  48. 316 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/util/CtwingRSAUtils.java
  49. 90 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/util/CtwingRequestUtil.java
  50. 306 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/util/HmacSha1Util.java
  51. 220 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/util/RSAUtil.java
  52. 66 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/util/StringUtil.java
  53. 120 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/util/XXTeaUtil.java
  54. 16 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-biz/src/main/java/com/sptg/permissions/biz/controller/AccountAuthenticationController.java
  55. 7 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-biz/src/main/java/com/sptg/permissions/biz/controller/AccountController.java
  56. 72 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-biz/src/main/java/com/sptg/permissions/biz/controller/AccountOauthController.java
  57. 22 23
      smart-house-yinchuan/sptg-permissions/sptg-permissions-biz/src/main/java/com/sptg/permissions/biz/controller/CustInfoVerifyController.java
  58. 66 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-biz/src/main/java/com/sptg/permissions/biz/controller/ThirdAuthenticationController.java
  59. 17 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-biz/src/main/java/com/sptg/permissions/biz/mapper/AccountOauthMapper.java
  60. 61 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-biz/src/main/java/com/sptg/permissions/biz/service/AccountOauthServiceInterface.java
  61. 2 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-biz/src/main/java/com/sptg/permissions/biz/service/AccountServiceInterface.java
  62. 114 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-biz/src/main/java/com/sptg/permissions/biz/service/impl/AccountOauthServiceImpl.java
  63. 9 0
      smart-house-yinchuan/sptg-permissions/sptg-permissions-biz/src/main/java/com/sptg/permissions/biz/service/impl/AccountServiceImpl.java
  64. 28 0
      szsq-boot-1/src/main/java/org/springblade/MyApplicationRunner.java
  65. 56 0
      szsq-boot-1/src/main/java/org/springblade/community/car/wrapper/CarWrapper.java
  66. 40 0
      szsq-boot-1/src/main/java/org/springblade/config/SpringSecurityActuatorConfig.java
  67. 36 0
      szsq-boot-1/src/main/java/org/springblade/config/Swagger2Config.java
  68. 25 0
      szsq-boot-1/src/main/java/org/springblade/config/SwaggerWebMvcConfigure.java
  69. 25 0
      szsq-boot-1/src/main/java/org/springblade/test/TestClass.java
  70. 29 0
      szsq-boot-2/src/main/java/org/springblade/config/SpringSecurityActuatorConfig.java

+ 1 - 0
smart-house-yinchuan/env_files/properties/dev.properties

@@ -8,6 +8,7 @@ mvn.spring.datasource.password=root@123456
 mvn.spring.redis.host=smart-house-redis
 mvn.spring.redis.port=6379
 mvn.spring.redis.password=
+mvn.spring.redis.database=12
 
 # RabbitMq
 mvn.spring.rabbitmq.host=smart-house-rabbitmq

+ 6 - 5
smart-house-yinchuan/sptg-common/sptg-common-core/src/main/java/com/sptg/common/core/util/aliface/FaceDetectUtil.java

@@ -11,6 +11,7 @@ import org.springframework.stereotype.Component;
 
 import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.List;
 
 @Component
 public class FaceDetectUtil {
@@ -66,12 +67,12 @@ public class FaceDetectUtil {
                 return new ResultBean("500.1", "照片有多个人脸,不合格!");
             }else{
 //                List<Float> poseList = data.getPoseList();
-                ArrayList<Double> poseList = (ArrayList<Double>) data.toMap().get("PoseList");
-                Double aDouble = poseList.get(0);
-                Double bDouble = poseList.get(1);
-                Double cDouble = poseList.get(2);
+                List<Float> poseList = data.getPoseList();
+                String aDouble = poseList.get(0) + "";
+                String bDouble = poseList.get(1) + "";
+                String cDouble = poseList.get(2) + "";
 
-                if (Math.abs(aDouble) > 10 || Math.abs(bDouble) > 10 || Math.abs(cDouble) > 10 ){
+                if (Math.abs(Double.valueOf(aDouble)) > 10 || Math.abs(Double.valueOf(bDouble)) > 10 || Math.abs(Double.valueOf(cDouble)) > 10 ){
                     // 人脸姿态不正确,不合格
                     return new ResultBean("500.1", "照片人脸姿态不正确,不合格!");
                 }else{

+ 11 - 11
smart-house-yinchuan/sptg-estate/sptg-estate-biz/src/main/java/com/sptg/estate/biz/service/impl/ApplyUserServiceImpl.java

@@ -191,17 +191,17 @@ public class ApplyUserServiceImpl extends ServiceImpl<ApplyUserMapper, ApplyUser
             }catch (Exception e){
                 return new ResultBean<>(ResultEnum.ERROR);
             }
-//            Assert.isTrue(timeRange, "请在7:00-22:00时间内进行审核!");
-//            if(StringUtils.isNotBlank(applyUser.getIdCard()) && StringUtils.isNotBlank(applyUser.getName())){
-//                CustInfoVerify custInfoVerify = new CustInfoVerify();
-//                custInfoVerify.setCustName(applyUser.getName());
-//                custInfoVerify.setCertNumber(applyUser.getIdCard());
-//                custInfoVerify.setCertType("1");
-//                boolean verify = custInfoVerifyFeign.verify(custInfoVerify);
-//                Assert.isTrue(verify, "身份证验证失败,请填写正确的身份证信息");
-//            }else{
-//                Assert.isTrue(false, "该住户没有身份证号,无法通过审核!");
-//            }
+            Assert.isTrue(timeRange, "请在7:00-22:00时间内进行审核!");
+            if(StringUtils.isNotBlank(applyUser.getIdCard()) && StringUtils.isNotBlank(applyUser.getName())){
+                CustInfoVerify custInfoVerify = new CustInfoVerify();
+                custInfoVerify.setCustName(applyUser.getName());
+                custInfoVerify.setCertNumber(applyUser.getIdCard());
+                custInfoVerify.setCertType("1");
+                boolean verify = custInfoVerifyFeign.verify(custInfoVerify);
+                Assert.isTrue(verify, "身份证验证失败,请填写正确的身份证信息");
+            }else{
+                Assert.isTrue(false, "该住户没有身份证号,无法通过审核!");
+            }
         }
 
         if (applyUser.getCheckState() == OperationConstant.ZERO) {

+ 2 - 2
smart-house-yinchuan/sptg-gateway/sptg-app-gateway/src/main/java/com/sptg/gateway/controller/MemberController.java

@@ -590,8 +590,8 @@ public class MemberController {
                 custInfoVerify.setCustName(name);
                 custInfoVerify.setCertNumber(id_card);
                 custInfoVerify.setCertType("1");
-//                boolean verify = custInfoVerifyFeign.verify(custInfoVerify);
-                boolean verify = true;
+                boolean verify = custInfoVerifyFeign.verify(custInfoVerify);
+//                boolean verify = true;
                 if(!verify){
                     hashMap.put("result_msg", "身份证验证失败,请填写正确的身份证信息");
                     return hashMap;

+ 28 - 4
smart-house-yinchuan/sptg-gateway/sptg-device-gateway/src/main/java/com/sptg/gateway/controller/FileUploadController.java

@@ -1,5 +1,6 @@
 package com.sptg.gateway.controller;
 
+import cn.hutool.core.io.FileTypeUtil;
 import com.github.tobato.fastdfs.domain.StorePath;
 import com.github.tobato.fastdfs.service.FastFileStorageClient;
 import com.sptg.common.core.beans.ResultBean;
@@ -21,15 +22,38 @@ public class FileUploadController {
 
     private final FastFileStorageClient fastFileStorageClient;
 
+    private static final String FILE_PNG=".png";
+    private static final String FILE_JPG=".jpg";
+    private static final String FILE_JPEG=".jpeg";
+
     /* -------------------------------------------------------------------------------------------------------------- */
 
     @PostMapping(value = "/common/file/upload")
     public ResultBean<StorePath> upload(@RequestParam("file") MultipartFile multipartFile)throws Exception{
         Assert.notNull(multipartFile,"参数异常");
-        long size = multipartFile.getSize();
-        String extension = FilenameUtils.getExtension(multipartFile.getOriginalFilename());
-        StorePath storePath = this.fastFileStorageClient.uploadFile(multipartFile.getInputStream(), size, extension, null);
-        return new ResultBean<>(ResultEnum.SUCCESS,storePath);
+        String filename = multipartFile.getOriginalFilename();
+        String fileType = filename.substring(filename.lastIndexOf("."));
+        //先判断后缀名
+        if (FILE_PNG.equalsIgnoreCase(fileType) || FILE_JPG.equalsIgnoreCase(fileType) || FILE_JPEG.equalsIgnoreCase(fileType)) {
+            String type ;
+            try {
+                type = FileTypeUtil.getType(multipartFile.getInputStream());
+                //根据首部字节判断文件类型
+                if (FILE_PNG.contains(type)||FILE_JPG.contains(type)||FILE_JPEG.contains(type)){
+                    long size = multipartFile.getSize();
+                    String extension = FilenameUtils.getExtension(multipartFile.getOriginalFilename());
+                    StorePath storePath = this.fastFileStorageClient.uploadFile(multipartFile.getInputStream(), size, extension, null);
+                    return new ResultBean<>(ResultEnum.SUCCESS,storePath);
+                }else{
+                    return new ResultBean(ResultEnum.FAILURE,"不支持的文件格式");
+                }
+            } catch (Exception e) {
+                return new ResultBean(ResultEnum.FAILURE,"不支持的文件格式");
+
+            }
+        }else{
+            return new ResultBean(ResultEnum.FAILURE,"不支持的文件格式");
+        }
     }
 
     @PostMapping(value = "/common/file/uploadBase64")

+ 32 - 8
smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/java/com/sptg/gateway/controller/common/FileManageController.java

@@ -1,5 +1,6 @@
 package com.sptg.gateway.controller.common;
 
+import cn.hutool.core.io.FileTypeUtil;
 import com.github.tobato.fastdfs.domain.StorePath;
 import com.github.tobato.fastdfs.service.FastFileStorageClient;
 import com.sptg.common.core.beans.ResultBean;
@@ -60,6 +61,9 @@ public class FileManageController {
     @Autowired
     private final ConfFeign confFeign;
     private final FaceVerifyFeign faceVerifyFeign;
+    private static final String FILE_PNG=".png";
+    private static final String FILE_JPG=".jpg";
+    private static final String FILE_JPEG=".jpeg";
 
     /**
      * 功能描述:文件上传
@@ -71,6 +75,34 @@ public class FileManageController {
      */
     @RequestMapping(value = "/upload")
     public ResultBean<StorePath> uploadFile(@RequestParam("file") MultipartFile multipartFile,Boolean isNeedMd5) throws Exception{
+        Assert.notNull(multipartFile,"参数异常");
+        String filename = multipartFile.getOriginalFilename();
+        String fileType = filename.substring(filename.lastIndexOf("."));
+        //先判断后缀名
+        if (FILE_PNG.equalsIgnoreCase(fileType) || FILE_JPG.equalsIgnoreCase(fileType) || FILE_JPEG.equalsIgnoreCase(fileType)) {
+            String type ;
+            try {
+                type = FileTypeUtil.getType(multipartFile.getInputStream());
+                //根据首部字节判断文件类型
+                if (FILE_PNG.contains(type)||FILE_JPG.contains(type)||FILE_JPEG.contains(type)){
+                    StorePathChildren storePath = this.getStorePathChildren(fastFileStorageClient.uploadFile(
+                            multipartFile.getInputStream(),multipartFile.getSize(),
+                            FilenameUtils.getExtension(multipartFile.getOriginalFilename()),null));
+                    if(isNeedMd5!=null && isNeedMd5){
+                        String md5Hex = DigestUtils.md5Hex(multipartFile.getInputStream());
+                        storePath.setMd5(md5Hex);
+                    }
+                    return new ResultBean<>(ResultEnum.SUCCESS,storePath);
+                }else{
+                    return new ResultBean(ResultEnum.FAILURE,"不支持的文件格式");
+                }
+            } catch (Exception e) {
+                return new ResultBean(ResultEnum.FAILURE,"不支持的文件格式");
+
+            }
+        }else{
+            return new ResultBean(ResultEnum.FAILURE,"不支持的文件格式");
+        }
         /*
          * 返回的对象storePath
          *  storePath.fullPath = "group1/M00/00/00/wKgAYlvpNveAQ9jgAACQxvfzaOY198.jpg"
@@ -83,14 +115,6 @@ public class FileManageController {
 //        if(StringUtils.hasText(size)){
 //            Assert.isTrue(this.checkFileSize(multipartFile.getSize(), 100, "M"), "文件大小不能超过100M");
 //        }
-        StorePathChildren storePath = this.getStorePathChildren(fastFileStorageClient.uploadFile(
-                multipartFile.getInputStream(),multipartFile.getSize(),
-                FilenameUtils.getExtension(multipartFile.getOriginalFilename()),null));
-        if(isNeedMd5!=null && isNeedMd5){
-            String md5Hex = DigestUtils.md5Hex(multipartFile.getInputStream());
-            storePath.setMd5(md5Hex);
-        }
-        return new ResultBean<>(ResultEnum.SUCCESS,storePath);
     }
 
     @PostMapping(value = "/uploadMaterialFile")

+ 202 - 0
smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/java/com/sptg/gateway/controller/permissions/ThirdAuthenticationController.java

@@ -0,0 +1,202 @@
+package com.sptg.gateway.controller.permissions;
+
+import com.alibaba.fastjson.JSONObject;
+import com.sptg.common.core.beans.ResultBean;
+import com.sptg.common.core.beans.ResultEnum;
+import com.sptg.common.core.constant.HttpConstant;
+import com.sptg.common.core.constant.SysLogConstant;
+import com.sptg.common.core.util.CookieUtils;
+import com.sptg.common.core.util.WebUtils;
+import com.sptg.common.security.annotation.Security;
+import com.sptg.common.security.service.SecurityServiceInterface;
+import com.sptg.permissions.api.dto.AccountOauthDto;
+import com.sptg.permissions.api.dto.LoginDto;
+import com.sptg.permissions.api.entity.Account;
+import com.sptg.permissions.api.entity.AccountOauth;
+import com.sptg.permissions.api.feigns.AccountAuthenticationFeign;
+import com.sptg.permissions.api.feigns.AccountFeign;
+import com.sptg.permissions.api.feigns.AccountOauthFeign;
+import com.sptg.permissions.api.thirdauth.constants.CtwingAuthConstants;
+import com.sptg.permissions.api.thirdauth.enums.AuthCustomizeSource;
+import com.sptg.permissions.api.thirdauth.util.ByteFormat;
+import com.sptg.permissions.api.thirdauth.util.StringUtil;
+import com.sptg.permissions.api.thirdauth.util.XXTeaUtil;
+import com.sptg.statistics.api.entity.SysOperationLog;
+import com.sptg.statistics.api.feigns.SysOperationLogFeign;
+import com.xkcoding.http.util.MapUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import me.zhyd.oauth.model.AuthCallback;
+import me.zhyd.oauth.model.AuthResponse;
+import me.zhyd.oauth.model.AuthUser;
+import me.zhyd.oauth.request.AuthRequest;
+import me.zhyd.oauth.utils.AuthStateUtils;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.sptg.permissions.api.thirdauth.util.AuthRequestUtil.getAuthRequest;
+
+/**
+ * title: AuthenticationController
+ * package: com.sptg.gateway.controller.permissions
+ * description: 用户认证-控制器
+ *
+ *                  
+ *                 
+ */
+@Slf4j
+@RestController
+@RequiredArgsConstructor
+@RequestMapping(value = "/permissions/third/authentication")
+public class ThirdAuthenticationController {
+
+    /* -------------------------------------------------- 接口注入 -------------------------------------------------- */
+
+    private final AccountAuthenticationFeign accountAuthenticationFeign;
+    private final SecurityServiceInterface<Account> securityServiceInterface;
+    private final SysOperationLogFeign sysOperationLogFeign;
+    private final AccountFeign accountFeign;
+    private final AccountOauthFeign accountOauthFeign;
+    /* --------------------------------------------------- 控制器 --------------------------------------------------- */
+
+    /**
+     * 功能描述: 访问授权
+     * @return ResultBean
+     *                  
+     *                       
+     */
+    @RequestMapping(value = "/render/{source}")
+    @ResponseBody
+    public void renderAuth(@PathVariable("source") String source, HttpServletResponse response) throws IOException {
+        log.warn("进入render:" + source);
+        AuthRequest authRequest = getAuthRequest(source);
+        String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
+        log.warn(authorizeUrl);
+        response.sendRedirect(authorizeUrl);
+    }
+
+    /**
+     * oauth平台中配置的授权回调地址,以本项目为例,在创建github授权应用时的回调地址应为:http://127.0.0.1:8443/oauth/callback/github
+     */
+    @RequestMapping("/callback/{source}")
+    public ModelAndView login(@PathVariable("source") String source, AuthCallback callback, HttpServletRequest request) {
+        AuthRequest authRequest = getAuthRequest(source);
+        callback = this.getAuthCallback(source, callback, request);
+        AuthResponse<AuthUser> response = authRequest.login(callback);
+        log.warn(JSONObject.toJSONString(response));
+
+        if (response.ok()) {
+            AuthUser data = response.getData();
+            AccountOauthDto accountOauthDto = new AccountOauthDto();
+            accountOauthDto.setMobile(data.getUsername());
+            accountOauthDto.setUuId(data.getUuid());
+            accountOauthDto.setSource(source);
+            ResultBean<AccountOauth> dbOauth = this.accountOauthFeign.getByUuIdAndSource(accountOauthDto);
+            Account dbAccount = this.accountFeign.getByUserMobile(accountOauthDto.getMobile());
+            if(dbOauth.getData() == null){
+                if(dbAccount == null){
+                    return new ModelAndView("common/guest-error");
+                }else{
+                    //自动绑定用户账号
+                    accountOauthDto.setAccountId(dbAccount.getId());
+                    ResultBean<Boolean> resultBean = this.accountOauthFeign.bindUser(accountOauthDto);
+                    if(!resultBean.getData()){
+                        return new ModelAndView("common/guest-error");
+                    }
+                }
+            }else{
+                this.accountOauthFeign.bindUser(accountOauthDto);
+            }
+            LoginDto loginDto = new LoginDto();
+            loginDto.setLoginName(dbAccount.getLoginName());
+            ResultBean<Account> resultBean = this.accountAuthenticationFeign.oauthLogin(loginDto);
+
+            //  用户信息
+            Account account = resultBean.getData();
+            //  创建用户令牌
+            String token = this.securityServiceInterface.createUserToken(account);
+            //  生成cookie
+            CookieUtils.setCookie(HttpConstant.ACCESS_TOKEN,token);
+            //  登录日志
+            SysOperationLog sysOperationLog = new SysOperationLog(SysLogConstant.LOGIN_EVENT,WebUtils.getIp(),account);
+            account.setLastLoginDate(new Date());
+            account.setLastLoginIp(WebUtils.getIp());
+            accountFeign.updateById(account);
+            sysOperationLogFeign.info(sysOperationLog);
+            return new ModelAndView("redirect:/");
+        }
+
+        Map<String, Object> map = new HashMap<>(1);
+        map.put("errorMsg", "登录异常,请重新登录");
+
+        return new ModelAndView("error", map);
+    }
+
+    private AuthCallback getAuthCallback(String source, AuthCallback authCallback, HttpServletRequest request){
+        if("ctwing".equals(source)){
+            String paras = request.getParameter("paras");
+            try {
+                // XXTea解密非公共加密参数
+                String decValue = new String(XXTeaUtil.decrypt(ByteFormat.hexToBytes(paras), CtwingAuthConstants.APP_SECRET.getBytes(CtwingAuthConstants.DEFAULT_CHARSET)));
+                Map<String, String> resultMap = MapUtil.parseStringToMap(decValue, false);
+                if(0 == Integer.valueOf(resultMap.get("result"))){
+                    authCallback.setCode(resultMap.get("code"));
+                    authCallback.setState(resultMap.get("state"));
+                }
+                log.warn(decValue);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        return authCallback;
+    }
+
+    @RequestMapping("/test/bindUser")
+    public ModelAndView test(AccountOauthDto accountOauthDto) {
+        //{"code":2000,"data":{"avatar":"http://avatar.e.189.cn/avatar/default/default_middle.jpg","email":"","nickname":"","source":"CTWING","token":{"accessToken":"5826e7983c5b423cb8f5ae83975d59bd","expireIn":7716616,"refreshToken":"218418f61c5f4758b75045578f0b3839","refreshTokenExpireIn":0},"username":"15622205184","uuid":"657f5c8dd9b819562fdcc672d218f4d2"}}
+        accountOauthDto.setSource("CTWING");
+        ResultBean<AccountOauth> dbOauth = this.accountOauthFeign.getByUuIdAndSource(accountOauthDto);
+        Account dbAccount = this.accountFeign.getByUserMobile(accountOauthDto.getMobile());
+        if(dbOauth.getData() == null){
+            if(dbAccount == null){
+                return new ModelAndView("common/guest-error");
+            }else{
+                //自动绑定用户账号
+                accountOauthDto.setAccountId(dbAccount.getId());
+                ResultBean<Boolean> resultBean = this.accountOauthFeign.bindUser(accountOauthDto);
+                if(!resultBean.getData()){
+                    return new ModelAndView("common/guest-error");
+                }
+            }
+        }else{
+            this.accountOauthFeign.bindUser(accountOauthDto);
+        }
+        LoginDto loginDto = new LoginDto();
+        loginDto.setLoginName(dbAccount.getLoginName());
+        ResultBean<Account> resultBean = this.accountAuthenticationFeign.oauthLogin(loginDto);
+
+        //  用户信息
+        Account account = resultBean.getData();
+        //  创建用户令牌
+        String token = this.securityServiceInterface.createUserToken(account);
+        //  生成cookie
+        CookieUtils.setCookie(HttpConstant.ACCESS_TOKEN,token);
+        //  登录日志
+        SysOperationLog sysOperationLog = new SysOperationLog(SysLogConstant.LOGIN_EVENT,WebUtils.getIp(),account);
+        account.setLastLoginDate(new Date());
+        account.setLastLoginIp(WebUtils.getIp());
+        accountFeign.updateById(account);
+        sysOperationLogFeign.info(sysOperationLog);
+        return new ModelAndView("redirect:/");
+    }
+
+}

+ 1 - 0
smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/ad/ad-material-add.js

@@ -55,6 +55,7 @@ layui.extend({
         , url: '/common/file/uploadMaterialFile?isNeedMd5=true'
         , accept: 'file' //文件:图片或者视频
         , auto: false
+        ,exts: 'jpg|png|jpeg'
         , bindAction: '#upload'
         , choose: function (obj) {
             var flag = true;

+ 1 - 0
smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/device/device-app-package-add.js

@@ -183,6 +183,7 @@ layui.extend({
     layui.upload.render({
         elem: '#fileUploadButton'
         , url: '/common/file/upload/?isNeedMd5=true'
+        ,exts: 'jpg|png|jpeg'
         , accept: 'file' //视频
         , before: function (obj) {
             //开启加载动画

+ 2 - 0
smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/estate/car-add.js

@@ -97,6 +97,7 @@ layui.extend({
     upload.render({
         elem: '#passport_upload'
         ,url: '/common/file/upload'
+        ,exts: 'jpg|png|jpeg'
         ,accept: 'images' //图片
         ,before: function(obj){
             $('#passport_upload').prev('.avatar').remove();
@@ -130,6 +131,7 @@ layui.extend({
     upload.render({
         elem: '#entry_upload'
         ,url: '/common/file/upload'
+        ,exts: 'jpg|png|jpeg'
         ,accept: 'images' //图片
         ,before: function(obj){
             $('#entry_upload').prev('.avatar').remove();

+ 2 - 0
smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/estate/car-edit.js

@@ -101,6 +101,7 @@ layui.extend({
     upload.render({
         elem: '#passport_upload'
         ,url: '/common/file/upload'
+        ,exts: 'jpg|png|jpeg'
         ,accept: 'images' //图片
         ,before: function(obj){
             $('#passport_upload').prev('.avatar').remove();
@@ -134,6 +135,7 @@ layui.extend({
     upload.render({
         elem: '#entry_upload'
         ,url: '/common/file/upload'
+        ,exts: 'jpg|png|jpeg'
         ,accept: 'images' //图片
         ,before: function(obj){
             $('#entry_upload').prev('.avatar').remove();

+ 1 - 0
smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/estate/notice-add.js

@@ -74,6 +74,7 @@ layui.extend({
         elem: '#uploadImage' //绑定元素
         ,url: '/common/file/upload?isNeedMd5=true' //上传接口
         ,acceptMime: 'image/*'
+        ,exts: 'jpg|png|jpeg'
         , auto: false
         ,choose: function(obj){
             var imgListId=$("#imgListId");

+ 2 - 0
smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/estate/parking-lot-add.js

@@ -97,6 +97,7 @@ layui.extend({
     upload.render({
         elem: '#passport_upload'
         ,url: '/common/file/upload'
+        ,exts: 'jpg|png|jpeg'
         ,accept: 'images' //图片
         ,before: function(obj){
             $('#passport_upload').prev('.avatar').remove();
@@ -130,6 +131,7 @@ layui.extend({
     upload.render({
         elem: '#entry_upload'
         ,url: '/common/file/upload'
+        ,exts: 'jpg|png|jpeg'
         ,accept: 'images' //图片
         ,before: function(obj){
             $('#entry_upload').prev('.avatar').remove();

+ 2 - 0
smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/estate/parking-lot-edit.js

@@ -97,6 +97,7 @@ layui.extend({
     upload.render({
         elem: '#passport_upload'
         ,url: '/common/file/upload'
+        ,exts: 'jpg|png|jpeg'
         ,accept: 'images' //图片
         ,before: function(obj){
             $('#passport_upload').prev('.avatar').remove();
@@ -130,6 +131,7 @@ layui.extend({
     upload.render({
         elem: '#entry_upload'
         ,url: '/common/file/upload'
+        ,exts: 'jpg|png|jpeg'
         ,accept: 'images' //图片
         ,before: function(obj){
             $('#entry_upload').prev('.avatar').remove();

+ 2 - 0
smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/estate/parking-space-add.js

@@ -97,6 +97,7 @@ layui.extend({
     upload.render({
         elem: '#passport_upload'
         ,url: '/common/file/upload'
+        ,exts: 'jpg|png|jpeg'
         ,accept: 'images' //图片
         ,before: function(obj){
             $('#passport_upload').prev('.avatar').remove();
@@ -130,6 +131,7 @@ layui.extend({
     upload.render({
         elem: '#entry_upload'
         ,url: '/common/file/upload'
+        ,exts: 'jpg|png|jpeg'
         ,accept: 'images' //图片
         ,before: function(obj){
             $('#entry_upload').prev('.avatar').remove();

+ 2 - 0
smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/estate/parking-space-edit.js

@@ -97,6 +97,7 @@ layui.extend({
     upload.render({
         elem: '#passport_upload'
         ,url: '/common/file/upload'
+        ,exts: 'jpg|png|jpeg'
         ,accept: 'images' //图片
         ,before: function(obj){
             $('#passport_upload').prev('.avatar').remove();
@@ -130,6 +131,7 @@ layui.extend({
     upload.render({
         elem: '#entry_upload'
         ,url: '/common/file/upload'
+        ,exts: 'jpg|png|jpeg'
         ,accept: 'images' //图片
         ,before: function(obj){
             $('#entry_upload').prev('.avatar').remove();

+ 1 - 0
smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/estate/repair-add.js

@@ -69,6 +69,7 @@ layui.extend({
     var uploadInst = upload.render({
         elem: '#uploadImage' //绑定元素
         ,url: '/common/file/upload?isNeedMd5=true' //上传接口
+        ,exts: 'jpg|png|jpeg'
         ,acceptMime: 'image/*'
         , auto: false
         ,choose: function(obj){

+ 2 - 0
smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/estate/user-add-view.js

@@ -144,6 +144,7 @@ layui.extend({
     upload.render({
         elem: '#passport_upload'
         ,url: '/common/file/upload'
+        ,exts: 'jpg|png|jpeg'
         ,accept: 'images' //图片
         ,before: function(obj){
             $('#passport_upload').prev('.avatar').remove();
@@ -177,6 +178,7 @@ layui.extend({
     upload.render({
         elem: '#entry_upload'
         ,url: '/common/file/upload'
+        ,exts: 'jpg|png|jpeg'
         ,accept: 'images' //图片
         ,before: function(obj){
             $('#entry_upload').prev('.avatar').remove();

+ 2 - 0
smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/estate/user-add.js

@@ -163,6 +163,7 @@ layui.extend({
     upload.render({
         elem: '#passport_upload'
         ,url: '/common/file/upload'
+        ,exts: 'jpg|png|jpeg'
         ,accept: 'images' //图片
         ,before: function(obj){
             $('#passport_upload').prev('.avatar').remove();
@@ -196,6 +197,7 @@ layui.extend({
     upload.render({
         elem: '#entry_upload'
         ,url: '/common/file/upload'
+        ,exts: 'jpg|png|jpeg'
         ,accept: 'images' //图片
         ,before: function(obj){
             $('#entry_upload').prev('.avatar').remove();

+ 2 - 0
smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/estate/user-edit.js

@@ -176,6 +176,7 @@ layui.extend({
     upload.render({
         elem: '#passport_upload'
         ,url: '/common/file/upload'
+        ,exts: 'jpg|png|jpeg'
         ,accept: 'images' //图片
         ,before: function(obj){
             $('#passport_upload').prev('.avatar').remove();
@@ -209,6 +210,7 @@ layui.extend({
     upload.render({
         elem: '#entry_upload'
         ,url: '/common/file/upload'
+        ,exts: 'jpg|png|jpeg'
         ,accept: 'images' //图片
         ,before: function(obj){
             $('#entry_upload').prev('.avatar').remove();

+ 1 - 0
smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/implement/project-detail.js

@@ -152,6 +152,7 @@ layui.extend({
         elem: '#uploadImage'
         ,url: '/common/file/upload'
         ,accept: 'images' //图片
+        ,exts: 'jpg|png|jpeg'
         ,multiple: true
         ,before: function(obj){
             //开启加载动画

+ 1 - 0
smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/implement/project-insert.js

@@ -213,6 +213,7 @@ layui.extend({
     upload.render({
         elem: '#uploadImage'
         ,url: '/common/file/upload'
+        ,exts: 'jpg|png|jpeg'
         ,accept: 'images' //图片
         ,multiple: true
         ,before: function(obj){

+ 1 - 0
smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/permissions/account-add.js

@@ -46,6 +46,7 @@ layui.extend({
             elem: '#file_upload'
             //  上传接口
             ,url: '/common/file/upload'
+            ,exts: 'jpg|png|jpeg'
             //  自动上传
             ,auto: true
             //  文件提交上传前的回调

+ 1 - 0
smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/permissions/account-edit.js

@@ -45,6 +45,7 @@ layui.extend({
             elem: '#file_upload'
             //  上传接口
             ,url: '/common/file/upload'
+            ,exts: 'jpg|png|jpeg'
             //  自动上传
             ,auto: true
             //  文件提交上传前的回调

+ 1 - 0
smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/permissions/account-setup.js

@@ -35,6 +35,7 @@ layui.extend({
         elem: '#file_upload'
         //  上传接口
         ,url: '/common/file/upload'
+        ,exts: 'jpg|png|jpeg'
         //  自动上传
         ,auto: true
         //  文件提交上传前的回调

+ 0 - 2
smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/permissions/password-change.js

@@ -23,7 +23,6 @@ layui.extend({
         //  提交表单
         layui.form.on("submit(entity_insert_filter)",function(data){
             common.timer($('button[lay-filter="entity_insert_filter"]'));
-            debugger
             $.ajax({
                 url     :   '/permissions/account/modifyPassword',
                 data    :   JSON.stringify(data.field),
@@ -31,7 +30,6 @@ layui.extend({
                 contentType : 'application/json',
                 type    :   'POST',
                 success :   function(res){
-                    debugger
                     if (res.code == 200){
                         window.location.href = '/permissions/authentication/login';
                     }else {

+ 1 - 0
smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/static/js/util/import-face-zip.js

@@ -36,6 +36,7 @@ layui.extend({
         elem: '#import'
         , multiple: false
         , accept: 'file'
+        ,exts: 'jpg|png|jpeg'
         , auto: false
         , bindAction: '#start_upload'
         , drag: true

+ 10 - 0
smart-house-yinchuan/sptg-gateway/sptg-housekeeper-gateway/src/main/resources/templates/common/guest-error.html

@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html lang="en" xmlns:th="http://www.thymeleaf.org">
+    <head>
+        <script th:replace="common/head"></script>
+    </head>
+    <body>
+        <h1>500</h1>
+        <p>请联系平台运营人员,开通物业账号!</p>
+    </body>
+</html>

+ 6 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-api/pom.xml

@@ -35,6 +35,12 @@
             <scope>compile</scope>
         </dependency>
 
+        <dependency>
+            <groupId>me.zhyd.oauth</groupId>
+            <artifactId>JustAuth</artifactId>
+            <version>1.16.5</version>
+        </dependency>
+
 
     </dependencies>
 

+ 30 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/dto/AccountOauthDto.java

@@ -0,0 +1,30 @@
+package com.sptg.permissions.api.dto;
+
+import com.baomidou.mybatisplus.annotations.TableField;
+import com.sptg.permissions.api.entity.Account;
+import com.sptg.permissions.api.entity.AccountOauth;
+import com.sptg.permissions.api.entity.AccountRole;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+/**
+ * title: AccountRoleDto
+ * package: com.sptg.permissions.api.dto
+ * description:
+ *
+ *                  
+ *                 
+ */
+@Setter
+@Getter
+public class AccountOauthDto extends AccountOauth {
+
+    /**
+     * 当前在线用户
+     */
+    @TableField(exist = false)
+    private Account onLineUser;
+
+}

+ 99 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/entity/AccountOauth.java

@@ -0,0 +1,99 @@
+package com.sptg.permissions.api.entity;
+
+import com.baomidou.mybatisplus.annotations.TableField;
+import com.baomidou.mybatisplus.annotations.TableId;
+import com.baomidou.mybatisplus.annotations.TableName;
+import com.baomidou.mybatisplus.enums.FieldStrategy;
+import com.baomidou.mybatisplus.enums.IdType;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * title: RoleMenu
+ * package: com.sptg.permissions.api.entity
+ * description: 账号角色关联-实体类
+ *
+ *                  
+ *                 
+ */
+@Getter
+@Setter
+@TableName(value = "account_oauth")
+public class AccountOauth {
+
+    /**
+     * 主键
+     */
+    @TableId(value = "l_id",type = IdType.AUTO)
+    private Long id;
+
+
+    @TableField(value = "l_account_id", strategy = FieldStrategy.IGNORED)
+    private Long accountId;
+
+    /**
+     * 第三方用户ID
+     */
+    @TableField(value = "s_uuId")
+    private String uuId;
+
+    /**
+     * 账户名
+     */
+    @TableField(value = "s_user_name")
+    private String userName;
+
+    /**
+     * 用户昵称
+     */
+    @TableField(value = "s_nick_name")
+    private String nickName;
+
+    /**
+     * 用户头像
+     */
+    @TableField(value = "s_avatar")
+    private String avatar;
+
+    /**
+     * 用户邮箱
+     */
+    @TableField(value = "s_email")
+    private String email;
+
+    /**
+     * 用户手机号
+     */
+    @TableField(value = "s_mobile")
+    private String mobile;
+
+    /**
+     * 用户来源
+     */
+    @TableField(value = "s_source")
+    private String source;
+
+    /**
+     * 删除标记:{ -1:已删除,0:正常 }
+     */
+    @TableField(value = "i_status")
+    private Integer status;
+
+    /**
+     * 创建时间
+     */
+    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
+    @TableField(value = "t_create_date")
+    private Date createDate;
+
+    /**
+     * 更新时间
+     */
+    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
+    @TableField(value = "t_update_date")
+    private Date updateDate;
+
+}

+ 2 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/enums/PermissionsEnum.java

@@ -63,6 +63,8 @@ public enum PermissionsEnum implements ResultBean.BaseResultEnum {
      */
     AUTHENTICATION_ERROR("401.1","用户名或密码错误"),
 
+    AUTHENTICATION_OAUTH_ERROR("401.2","用户授权登录失败"),
+
     /* ---------------------------------------------- 403.数据权限异常 ---------------------------------------------- */
 
     /**

+ 8 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/feigns/AccountAuthenticationFeign.java

@@ -41,6 +41,14 @@ public interface AccountAuthenticationFeign {
     @PostMapping(value ="/account/login")
     ResultBean<Account> login(@RequestBody LoginDto loginDto);
 
+    /**
+     * 用户第三方授权登陆接口
+     * @param loginDto 登陆接口数据传输对象
+     * @return ResultBean<AccountDto> 若登陆成功,则返回用户信息.
+     */
+    @PostMapping(value ="/account/oauth/login")
+    ResultBean<Account> oauthLogin(@RequestBody LoginDto loginDto);
+
     /**
      * 功能描述: 重新加载账号信息
      * @param id 账号Id

+ 10 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/feigns/AccountFeign.java

@@ -147,4 +147,14 @@ public interface AccountFeign {
 
     @PostMapping(value = "/account/modifyPassword")
     ResultBean<Boolean> modifyPassword(@RequestBody Account account);
+
+    /**
+     * 功能描述: 根据用户手机号获取账号信息
+     * @param userMobile 用户手机号
+     * @return Account
+     *
+     *
+     */
+    @GetMapping(value = "/account/getByUserMobile")
+    Account getByUserMobile(@RequestParam(value = "userMobile") String userMobile);
 }

+ 65 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/feigns/AccountOauthFeign.java

@@ -0,0 +1,65 @@
+package com.sptg.permissions.api.feigns;
+
+import com.baomidou.mybatisplus.plugins.Page;
+import com.sptg.common.core.beans.PageBean;
+import com.sptg.common.core.beans.ResultBean;
+import com.sptg.permissions.api.dto.AccountDto;
+import com.sptg.permissions.api.dto.AccountOauthDto;
+import com.sptg.permissions.api.entity.Account;
+import com.sptg.permissions.api.entity.AccountOauth;
+import com.sptg.permissions.api.feigns.fallback.AccountOauthFeignFallbackFactory;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+
+/**
+ * title: AccountOauthFeign
+ * package: com.sptg.permissions.api.feigns
+ * description: 账号角色对外服务接口
+ *
+ *                  
+ *                 
+ */
+@FeignClient(value = "smart-house-permissions",fallbackFactory = AccountOauthFeignFallbackFactory.class)
+public interface AccountOauthFeign {
+
+    /**
+     * 功能描述: 根据角色Id查询,分页绑定的账号列表
+     * @param pageBean 查询条件{ roleId,当前登陆用户,分页条件为必填 }
+     * @return ResultBean<Page>
+     *                  
+     *                       
+     */
+    @PostMapping(value = "/account/oauth/pagingQuery")
+    ResultBean<Page> pagingQuery(PageBean<AccountOauth, AccountOauthDto> pageBean);
+
+    /**
+     * 功能描述: 获取单个授权用户
+     * @param dto { accountId:必填,roleId:必填 }
+     * @return ResultBean<Boolean>
+     *
+     *
+     */
+    @PostMapping(value = "/account/oauth/getByUuIdAndSource")
+    ResultBean<AccountOauth> getByUuIdAndSource(AccountOauthDto dto);
+
+
+    /**
+     * 功能描述: 绑定用户
+     * @param dto { accountId:必填,roleId:必填 }
+     * @return ResultBean<Boolean>
+     *                  
+     *                       
+     */
+    @PostMapping(value = "/account/oauth/bind")
+    ResultBean<Boolean> bindUser(AccountOauthDto dto);
+
+    /**
+     * 功能描述: 解除用户绑定
+     * @param dto { accountId:必填,accountIds:必填 }
+     * @return ResultBean<Boolean>
+     *                  
+     *                       
+     */
+    @PostMapping(value = "/account/oauth/untie")
+    ResultBean<Boolean> untieUser(AccountOauthDto dto);
+}

+ 38 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/feigns/ThirdAuthenticationFeign.java

@@ -0,0 +1,38 @@
+package com.sptg.permissions.api.feigns;
+
+import com.sptg.common.core.beans.ResultBean;
+import com.sptg.permissions.api.dto.AccountDto;
+import com.sptg.permissions.api.dto.LoginDto;
+import com.sptg.permissions.api.entity.Account;
+import com.sptg.permissions.api.feigns.fallback.ThirdAuthenticationFeignFallbackFactory;
+import me.zhyd.oauth.model.AuthCallback;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.Serializable;
+
+
+/**
+ * title: ThirdAuthenticationFeign
+ * package: com.sptg.permissions.api.feigns
+ * description: 认证相关接口
+ *
+ *                  
+ *                 
+ */
+@FeignClient(value = "smart-house-permissions",fallbackFactory = ThirdAuthenticationFeignFallbackFactory.class)
+public interface ThirdAuthenticationFeign {
+
+    @RequestMapping("/render/{source}")
+    @ResponseBody
+    void renderAuth(@PathVariable("source") String source, HttpServletResponse response) throws IOException;
+
+    @RequestMapping("/callback/{source}")
+    ModelAndView login(@PathVariable("source") String source, AuthCallback callback, HttpServletRequest request);
+
+
+}

+ 5 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/feigns/fallback/AccountAuthenticationFeignFallbackFactory.java

@@ -39,6 +39,11 @@ public class AccountAuthenticationFeignFallbackFactory implements FallbackFactor
                 return new ResultBean<>(ResultEnum.ERROR);
             }
 
+            @Override
+            public ResultBean<Account> oauthLogin(LoginDto loginDto) {
+                return null;
+            }
+
             @Override
             public Account reload(Serializable id) {
                 log.error(cause.getMessage(), cause);

+ 5 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/feigns/fallback/AccountFeignFallbackFactory.java

@@ -128,6 +128,11 @@ public class AccountFeignFallbackFactory implements FallbackFactory<AccountFeign
                 log.error(cause.getMessage(),cause);
                 return null;
             }
+
+            @Override
+            public Account getByUserMobile(String userMobile) {
+                return null;
+            }
         };
     }
 }

+ 58 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/feigns/fallback/AccountOauthFeignFallbackFactory.java

@@ -0,0 +1,58 @@
+package com.sptg.permissions.api.feigns.fallback;
+
+import com.baomidou.mybatisplus.plugins.Page;
+import com.sptg.common.core.beans.PageBean;
+import com.sptg.common.core.beans.ResultBean;
+import com.sptg.common.core.beans.ResultEnum;
+import com.sptg.permissions.api.dto.AccountDto;
+import com.sptg.permissions.api.dto.AccountOauthDto;
+import com.sptg.permissions.api.dto.AccountOauthDto;
+import com.sptg.permissions.api.entity.Account;
+import com.sptg.permissions.api.entity.AccountOauth;
+import com.sptg.permissions.api.entity.AccountOauth;
+import com.sptg.permissions.api.feigns.AccountOauthFeign;
+import com.sptg.permissions.api.feigns.AccountOauthFeign;
+import feign.hystrix.FallbackFactory;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+/**
+ * title: AccountOauthFeignFallbackFactory
+ * package: com.sptg.permissions.api.feigns.fallback
+ * description: 账号角色对外服务接口-容错处理
+ *
+ *                  
+ *                 
+ */
+@Component
+@Slf4j
+public class AccountOauthFeignFallbackFactory implements FallbackFactory<AccountOauthFeign> {
+
+    @Override
+    public AccountOauthFeign create(Throwable cause) {
+        return new AccountOauthFeign(){
+            @Override
+            public ResultBean<Page> pagingQuery(PageBean<AccountOauth, AccountOauthDto> pageBean) {
+                log.error(cause.getMessage(), cause);
+                return new ResultBean<>(ResultEnum.ERROR);
+            }
+
+            @Override
+            public ResultBean<AccountOauth> getByUuIdAndSource(AccountOauthDto dto) {
+                return null;
+            }
+
+            @Override
+            public ResultBean<Boolean> bindUser(AccountOauthDto dto) {
+                log.error(cause.getMessage(), cause);
+                return new ResultBean<>(ResultEnum.ERROR);
+            }
+
+            @Override
+            public ResultBean<Boolean> untieUser(AccountOauthDto dto) {
+                log.error(cause.getMessage(), cause);
+                return new ResultBean<>(ResultEnum.ERROR);
+            }
+        };
+    }
+}

+ 47 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/feigns/fallback/ThirdAuthenticationFeignFallbackFactory.java

@@ -0,0 +1,47 @@
+package com.sptg.permissions.api.feigns.fallback;
+
+import com.sptg.common.core.beans.ResultBean;
+import com.sptg.common.core.beans.ResultEnum;
+import com.sptg.permissions.api.dto.AccountDto;
+import com.sptg.permissions.api.dto.LoginDto;
+import com.sptg.permissions.api.entity.Account;
+import com.sptg.permissions.api.feigns.ThirdAuthenticationFeign;
+import feign.hystrix.FallbackFactory;
+import lombok.extern.slf4j.Slf4j;
+import me.zhyd.oauth.model.AuthCallback;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.Serializable;
+
+/**
+ * title: ThirdAuthenticationFeignFallbackFactory
+ * package: com.sptg.permissions.api.feigns.fallback
+ * description: 认证授权相关接口-容错处理
+ *
+ *                  
+ *                 
+ */
+@Component
+@Slf4j
+public class ThirdAuthenticationFeignFallbackFactory implements FallbackFactory<ThirdAuthenticationFeign> {
+
+    @Override
+    public ThirdAuthenticationFeign create(Throwable cause){
+        return new ThirdAuthenticationFeign() {
+            @Override
+            public void renderAuth(String source, HttpServletResponse response) throws IOException {
+
+            }
+
+            @Override
+            public ModelAndView login(String source, AuthCallback callback, HttpServletRequest request) {
+                return null;
+            }
+
+        };
+    }
+}

+ 94 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/constants/CtwingAuthConstants.java

@@ -0,0 +1,94 @@
+package com.sptg.permissions.api.thirdauth.constants;
+
+/**
+ * @author: Chenzhenyong
+ * @description: 常量工具类
+ * @date: Created in 12:25 2018/7/24
+ */
+public class CtwingAuthConstants {
+
+    /**
+     * 应用ID
+     */
+    public static final String APP_ID = "8135892866";
+
+    /**
+     * 应用秘钥(用于xxtea加密)
+     */
+    public static final String APP_SECRET = "SnpYtQuSDrb3igRzIzFerfLxOMTC8sd2";
+
+
+    public static final String DEFAULT_CHARSET = "UTF-8";
+
+    /**
+     * wap登录框地址
+     */
+    public static final String UNIFY_ACCOUNT_LOGIN_URL = "https://open.e.189.cn/api/logbox/oauth2/separate/unifyAccountLogin.do";
+
+    /**
+     * 通过code获取accessToken接口
+     */
+    public static final String ACCESS_TOKEN_URL = "https://open.e.189.cn/api/logbox/oauth2/accessToken.do";
+
+    /**
+     * 获取用户信息
+     */
+//    public static final String GET_USER_INFO = "https://openeop.dcoos.189.cn:8100/serviceAgent/rest/openapi/asymauth/gbcs/getUserInfo";
+    public static final String GET_USER_INFO = "https://open.e.189.cn/openapi/asymauth/gbcs/getUserInfo.do";
+
+
+
+    /**
+     * 客户端类型,统一为:10010
+     */
+    public static final String clientType = "10010";
+
+    /**
+     * 统一为:redirect(用于重定向接口的显示说明)
+     */
+    public static final String format = "redirect";
+
+    /**
+     * 调用的接口版本号:v2.0
+     */
+    public static final String version = "v2.0";
+
+
+
+    /**
+     * 重定向返回URL(returnURL如带参数,整个returnURL需进行URL编码)
+     */
+    public static final String returnURL = "http://73zbyp7slu.51xd.pub/permissions/third/authentication/callback/ctwing";
+
+    /**
+     * 值为normal或popping(normal为正常嵌入页面,popping为弹出式页面,默认normal)
+     */
+    public static final String pageKey = "normal";
+
+    /**
+     * 注册成功后返回的URL(登录框右下角注册链接)。默认注册后返回天翼账号,如需注册后返回接入方,可传入该参数。
+     * (regReturnUrl如带参数,整个regReturnUrl需进行URL编码)
+     */
+    public static final String regReturnUrl = "";
+
+    /**
+     * 用于保持请求和回调的状态,登录请求后原样带回给第三方。
+     * 该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验
+     */
+    public static final String state = "";
+
+    public static final String PUB_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjUQ/6RRiVTBVfpV6mTLdcQY8NUroBBwFGBHLQ8Vw9kmifanKOv5Nr8WfG4P89Cywi35hkEVIQRnacgEmb+7+ZjX3jYmwbeZ2HON1eZ9U0eUTpGvaJ+XxyJ4GLakD59gVRXYBmA+Fo0Tonn1owVhKCETKQyYUDsn6i4qRkcKLPtQIDAQAB";
+
+    public static final String PRI_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKNRD/pFGJVMFV+lXqZMt1xBjw1SugEHAUYEctDxXD2SaJ9qco6/k2vxZ8bg/z0LLCLfmGQRUhBGdpyASZv7v5mNfeNibBt5nYc43V5n1TR5ROka9on5fHIngYtqQPn2BVFdgGYD4WjROiefWjBWEoIRMpDJhQOyfqLipGRwos+1AgMBAAECgYEAhWSbkUZIiwEm4AV5Zol4psDhb/dm95naH29YvHK3bY8dJ0BRq2isp9j4c4eo0hpDBYTtuqYvCh4TmUZrWR1p41ggAxx8/5WC2rGqUzdYyPdbG8Q/O5ko8YtBx+LuZsRtvQtVEbxMZfV8XoRUe9JrkOEyzTpVBKiriF8s/qU6vGECQQDm7aMAfWZC1jp7dwP2SkmVxrGll7OskiunpbUc6Whon9Qyo/wwohRwjWXr+p64w1ysFlicITW2iR12TZ8ceypJAkEAtQw+vChf1c12n0GDvdjBWPp7vGKXkmgJRgSnmRl782ddvdgqjmwlDkkyC/fhMyRANN8C9R+EGMb39G52xWRaDQJAbxbsbiTlF8wE8DYN0uJjych+1yFGTwM2OvztRo5GKuaQZxgaDq850/dBi6bRyiI5J5PMZrdXJouJf8rRexsI+QJAfABqC4d/tDlosMU3jVUjgGT3UN0aQX2eNGXFwNeyjNDUZM3kv+2UJ8e8TnQ1u0ht7Yh9RxSR7kKA29q44JPOFQJAQkWGIcMjAO9vrPlJjNEYll/ej+QHpCZ8ofzv4QWLrFIUNBqVamWTaI87BWCb4exPn86D+MXOHxC7YWlD+vykIg==";
+
+    //用户获取用户信息
+    public static final String Client_Id = "8261935660391399424";
+
+    //用户获取用户信息
+    public static final String X_APP_ID = "4749e5bf9236e7a8965dda936d5c30c6";
+
+    //用户获取用户信息
+    public static final String X_APP_KEY = "ae9e9ce926b03fcc225cdb94730154c";
+
+
+}

+ 30 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/enums/AuthCustomizeSource.java

@@ -0,0 +1,30 @@
+package com.sptg.permissions.api.thirdauth.enums;
+
+import com.sptg.permissions.api.thirdauth.constants.CtwingAuthConstants;
+import com.sptg.permissions.api.thirdauth.request.AuthCtwingRequest;
+import me.zhyd.oauth.config.AuthSource;
+import me.zhyd.oauth.request.AuthDefaultRequest;
+
+public enum  AuthCustomizeSource implements AuthSource {
+
+    CTWING {
+        @Override
+        public String authorize() {
+            return CtwingAuthConstants.UNIFY_ACCOUNT_LOGIN_URL;
+        }
+        @Override
+        public String accessToken() {
+            return CtwingAuthConstants.ACCESS_TOKEN_URL;
+        }
+        @Override
+        public String userInfo() {
+            return CtwingAuthConstants.GET_USER_INFO;
+        }
+        @Override
+        public Class<? extends AuthDefaultRequest> getTargetClass() {
+            return AuthCtwingRequest.class;
+        }
+    };
+
+    private AuthCustomizeSource() { }
+}

+ 109 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/officedemo/CtwingUnifyAccountLoginDemo.java

@@ -0,0 +1,109 @@
+package com.sptg.permissions.api.thirdauth.officedemo;
+
+import com.sptg.permissions.api.thirdauth.constants.CtwingAuthConstants;
+import com.sptg.permissions.api.thirdauth.util.ByteFormat;
+import com.sptg.permissions.api.thirdauth.util.HmacSha1Util;
+import com.sptg.permissions.api.thirdauth.util.XXTeaUtil;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author lizhb
+ * @date 2022/07/27
+ */
+@Slf4j
+public class CtwingUnifyAccountLoginDemo {
+
+    public static void main(String[] args) {
+        try {
+            // 注意:运行demo前请将天翼账号开放平台申请获取的应用ID(appId)、应用秘钥(appSecret)填写至Constants类中。
+            // 运行前请在Constants类中填写或修改请求所需参数
+
+            // 公共请求参数
+            // 开发者在天翼账号开放平台申请获取的应用ID
+            String appId = CtwingAuthConstants.APP_ID;
+            // 统一为:20100
+            String clientType = CtwingAuthConstants.clientType;
+            // 统一为:redirect(用于重定向接口的显示说明)
+            String format = CtwingAuthConstants.format;
+            // 调用的接口版本号:v2.1
+            String version = CtwingAuthConstants.version;
+            // 加密参数
+            String paras = getParas();
+
+            // 签名所需参数map
+            Map<String, String> signMap = new HashMap<>();
+            signMap.put("appId", appId);
+            signMap.put("clientType", clientType);
+            signMap.put("format", format);
+            signMap.put("version", version);
+            signMap.put("paras", paras);
+
+            // 签名
+            String sign = getSign(signMap);
+
+            // 拼接wap登录框链接(GET请求)
+            String webLoginBxUrl = CtwingAuthConstants.UNIFY_ACCOUNT_LOGIN_URL + "?" + "appId=" + appId + "&clientType=" + clientType
+                    + "&format=" + format + "&version=" + version + "&paras=" + paras + "&sign=" + sign;
+
+            log.info("generate loginbox web url unifyAccountLogin success.");
+            log.info("unifyAccountLogin url : " + webLoginBxUrl);
+
+            // ps: 将生成的链接wapLoginBxUrl复制到浏览器中访问
+            // 链接返回wap登录框界面,登录成功后重定向到指定的URL
+            // 如http://returnURL?appId=123&paras=123&sign=123。returnURL按照本接口规范定义的参数处理方式接收和处理。
+
+        } catch (Exception e){
+            log.error("unifyAccountLogin demo error:",e);
+        }
+    }
+
+
+    /**
+     * 生成paras参数方法
+     * @return
+     */
+    private static String getParas() throws Exception {
+        // 非公共请求参数
+        Map<String, String> businessMap = new HashMap<>();
+        // 时间戳
+        businessMap.put("timeStamp", String.valueOf(System.currentTimeMillis()));
+        // 回调地址
+        businessMap.put("returnURL", CtwingAuthConstants.returnURL);
+        // 页面Key
+        businessMap.put("pageKey", CtwingAuthConstants.pageKey);
+        // 登录类型
+        businessMap.put("regReturnUrl", CtwingAuthConstants.regReturnUrl);
+        // 状态参数
+        businessMap.put("state", CtwingAuthConstants.state);
+
+        // 拼接非公共请求参数(无顺序要求)
+        StringBuffer sb = new StringBuffer();
+        for(Map.Entry<String, String> entry : businessMap.entrySet()) {
+            sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
+        }
+
+        // XXTea加密非公共加密参数
+        byte[] encValue = XXTeaUtil.encrypt(sb.toString().getBytes(CtwingAuthConstants.DEFAULT_CHARSET)
+                , CtwingAuthConstants.APP_SECRET.getBytes(CtwingAuthConstants.DEFAULT_CHARSET));
+        return ByteFormat.bytesToHexString(encValue);
+    }
+
+    /**
+     * 获取签名参数方法
+     * @param signMap
+     * @return
+     */
+    private static String getSign(Map<String, String> signMap) throws Exception {
+        // 生成签名加密串(拼接顺序为:appId+clientType+format+version+paras)
+        String signValue = signMap.get("appId") + signMap.get("clientType") + signMap.get("format")
+                + signMap.get("version") + signMap.get("paras");
+
+        // HMAC-SHA1签名
+        byte[] encValue = HmacSha1Util.getHmacSHA1(signValue, CtwingAuthConstants.APP_SECRET);
+        return ByteFormat.bytesToHexString(encValue);
+    }
+
+}

+ 216 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/request/AuthCtwingRequest.java

@@ -0,0 +1,216 @@
+package com.sptg.permissions.api.thirdauth.request;
+
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.sptg.permissions.api.thirdauth.constants.CtwingAuthConstants;
+import com.sptg.permissions.api.thirdauth.enums.AuthCustomizeSource;
+import com.sptg.permissions.api.thirdauth.util.*;
+import com.xkcoding.http.util.StringUtil;
+import me.zhyd.oauth.config.AuthConfig;
+import me.zhyd.oauth.exception.AuthException;
+import me.zhyd.oauth.model.AuthCallback;
+import me.zhyd.oauth.model.AuthToken;
+import me.zhyd.oauth.model.AuthUser;
+import me.zhyd.oauth.request.AuthDefaultRequest;
+import me.zhyd.oauth.utils.StringUtils;
+import me.zhyd.oauth.utils.UrlBuilder;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class AuthCtwingRequest extends AuthDefaultRequest {
+
+    public AuthCtwingRequest(AuthConfig config) {
+        super(config, AuthCustomizeSource.CTWING);
+    }
+
+    @Override
+    protected AuthToken getAccessToken(AuthCallback authCallback) {
+        String response = this.doPostAuthorizationCode(authCallback.getCode());
+        return this.getAuthToken(response);
+    }
+
+    @Override
+    protected AuthUser getUserInfo(AuthToken authToken) {
+        String userInfo = this.doGetUserInfo(authToken);
+        if(StringUtil.isEmpty(userInfo)){
+            throw new AuthException("认证失败");
+        }
+        JSONObject object = JSONObject.parseObject(userInfo);
+        this.checkGetUserInfoResponse(object);
+        try {
+            String dataStr = CtwingRSAUtils.decryptByPrivateKeyForLongStr(object.getString("data"), CtwingAuthConstants.PRI_KEY);
+            JSONObject data = JSONObject.parseObject(dataStr);
+            return AuthUser.builder()
+                    .uuid(data.getString("openId"))
+                    .nickname(data.getString("nickName"))
+                    .email(data.getString("email"))
+                    .avatar(data.getString("userIconUrl2"))
+                    .username(data.getString("mobile"))
+                    .token(authToken).source(this.source.toString()).build();
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+
+    }
+
+    @Override
+    public String doGetUserInfo(AuthToken authToken) {
+        String response = this.userInfoUrl(authToken);
+        return response;
+    }
+
+    private String getAvatar(JSONObject object) {
+        String protrait = object.getString("portrait");
+        return StringUtils.isEmpty(protrait) ? null : String.format("http://himg.bdimg.com/sys/portrait/item/%s.jpg", protrait);
+    }
+
+    @Override
+    public String authorize(String state) {
+        // 签名所需参数map
+        String paras = getParas(state);
+        return UrlBuilder.fromBaseUrl(super.authorize(state))
+                .queryParam("appId", CtwingAuthConstants.APP_ID)
+                .queryParam("clientType", CtwingAuthConstants.clientType)
+                .queryParam("format", CtwingAuthConstants.format)
+                .queryParam("version", CtwingAuthConstants.version)
+                .queryParam("paras", paras)
+                .queryParam("sign", this.getCodeSign(CtwingAuthConstants.APP_ID, CtwingAuthConstants.clientType, CtwingAuthConstants.format, CtwingAuthConstants.version, paras))
+                .build();
+    }
+
+    @Override
+    public String accessTokenUrl(String code){
+        return UrlBuilder.fromBaseUrl(super.source.accessToken())
+                .queryParam("code", code)
+                .queryParam("appId", CtwingAuthConstants.APP_ID)
+                .queryParam("client_id", this.config.getClientId())
+                .queryParam("client_secret", this.config.getClientSecret())
+                .queryParam("grantType", "authorization_login")
+                .queryParam("format", "json")
+                .queryParam("sign", getAccessTokenSign(CtwingAuthConstants.APP_ID, code, "json", "authorization_login"))
+                .build();
+    }
+
+    @Override
+    public String userInfoUrl(AuthToken authToken) {
+        String response = null;
+        String timeStamp = String.valueOf(System.currentTimeMillis());
+        Map<String, String> generalParamsMap = new HashMap<>(0);
+        Map<String, String> businessParamsMap = new HashMap<>(0);
+        businessParamsMap.put("accessToken", authToken.getAccessToken());
+        try {
+            String params = CtwingRequestUtil.generateParams(businessParamsMap, CtwingAuthConstants.APP_SECRET);
+            generalParamsMap.put("clientId", CtwingAuthConstants.APP_ID);
+            generalParamsMap.put("timeStamp", timeStamp);
+            generalParamsMap.put("format", "json");
+            generalParamsMap.put("params", params);
+            String sign = CtwingRequestUtil.generateSign(generalParamsMap, CtwingAuthConstants.PRI_KEY);
+            generalParamsMap.put("sign", sign);
+            StringBuffer sb = new StringBuffer();
+            for(Map.Entry<String, String> entry : generalParamsMap.entrySet()){
+                sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
+            }
+            JSONObject jsonObject = new JSONObject();
+            jsonObject.put("clientId", CtwingAuthConstants.APP_ID);
+            jsonObject.put("timeStamp", timeStamp);
+            jsonObject.put("format", "json");
+            jsonObject.put("params", params);
+            jsonObject.put("sign", sign);
+            System.out.println(CtwingAuthConstants.GET_USER_INFO + "?" + sb.toString());
+            Map<String, String> httpHeader = new HashMap<>();
+            httpHeader.put("X-APP-KEY", CtwingAuthConstants.X_APP_KEY);
+            httpHeader.put("X-APP-ID", CtwingAuthConstants.X_APP_ID);
+            HttpRequest postRequest = HttpUtil.createPost(CtwingAuthConstants.GET_USER_INFO);
+            postRequest.addHeaders(httpHeader);
+            postRequest.form(jsonObject);
+            postRequest.timeout(10000);
+            postRequest.contentType("application/x-www-form-urlencoded;charset=utf-8");
+            response = postRequest.execute().body();
+            return response;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    private void checkAccessTokenResponse(JSONObject object) {
+        Integer result = object.getInteger("result");
+        if(result != 10000){
+            throw new AuthException(object.getString("msg"));
+        }
+    }
+
+    private void checkGetUserInfoResponse(JSONObject object) {
+        String result = object.getString("result");
+        if(!"0".equals(result)){
+            throw new AuthException(object.getString("msg"));
+        }
+    }
+
+    private AuthToken getAuthToken(String response) {
+        JSONObject accessTokenObject = JSONObject.parseObject(response);
+        this.checkAccessTokenResponse(accessTokenObject);
+        return AuthToken.builder().accessToken(accessTokenObject.getString("accessToken")).refreshToken(accessTokenObject.getString("refreshToken")).scope(accessTokenObject.getString("scope")).expireIn(accessTokenObject.getIntValue("rfExpiresIn")).build();
+    }
+
+    private String getParas(String state){
+        try{
+            // 非公共请求参数
+            Map<String, String> businessMap = new HashMap<>();
+            // 时间戳
+            businessMap.put("timeStamp", String.valueOf(System.currentTimeMillis()));
+            // 回调地址
+            businessMap.put("returnURL", CtwingAuthConstants.returnURL);
+            // 页面Key
+            businessMap.put("pageKey", CtwingAuthConstants.pageKey);
+            // 登录类型
+            businessMap.put("regReturnUrl", CtwingAuthConstants.regReturnUrl);
+            // 状态参数
+            businessMap.put("state", state);
+
+            // 拼接非公共请求参数(无顺序要求)
+            StringBuffer sb = new StringBuffer();
+            for(Map.Entry<String, String> entry : businessMap.entrySet()) {
+                sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
+            }
+
+            // XXTea加密非公共加密参数
+            byte[] encValue = XXTeaUtil.encrypt(sb.toString().getBytes(CtwingAuthConstants.DEFAULT_CHARSET)
+                    , CtwingAuthConstants.APP_SECRET.getBytes(CtwingAuthConstants.DEFAULT_CHARSET));
+            return ByteFormat.bytesToHexString(encValue);
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    private String getCodeSign(String appId, String clientType, String format, String version, String paras){
+        try{
+            String signValue = appId + clientType + format + version + paras;
+
+            // HMAC-SHA1签名
+            byte[] encValue = HmacSha1Util.getHmacSHA1(signValue, CtwingAuthConstants.APP_SECRET);
+            return ByteFormat.bytesToHexString(encValue);
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    private String getAccessTokenSign(String appId, String code, String format, String grantType){
+        try{
+            String signValue = appId + code + format + grantType;
+
+            // HMAC-SHA1签名
+            byte[] encValue = HmacSha1Util.getHmacSHA1(signValue, CtwingAuthConstants.APP_SECRET);
+            return ByteFormat.bytesToHexString(encValue);
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+}

+ 34 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/util/AuthRequestUtil.java

@@ -0,0 +1,34 @@
+package com.sptg.permissions.api.thirdauth.util;
+
+import com.sptg.permissions.api.thirdauth.request.AuthCtwingRequest;
+import me.zhyd.oauth.config.AuthConfig;
+import me.zhyd.oauth.exception.AuthException;
+import me.zhyd.oauth.request.*;
+
+public class AuthRequestUtil {
+
+    /**
+     * 根据具体的授权来源,获取授权请求工具类
+     *
+     * @param source
+     * @return
+     */
+    public static AuthRequest getAuthRequest(String source) {
+        AuthRequest authRequest = null;
+        switch (source.toUpperCase()) {
+            case "CTWING":
+                authRequest = new AuthCtwingRequest(AuthConfig.builder()
+                        .clientId("8135892866")
+                        .clientSecret("SnpYtQuSDrb3igRzIzFerfLxOMTC8sd2")
+                        .redirectUri("http://73zbyp7slu.51xd.pub/permissions/third/authentication/callback/ctwing")
+                        .build());
+                break;
+            default:
+                break;
+        }
+        if (null == authRequest) {
+            throw new AuthException("未获取到有效的Auth配置");
+        }
+        return authRequest;
+    }
+}

+ 51 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/util/ByteFormat.java

@@ -0,0 +1,51 @@
+package com.sptg.permissions.api.thirdauth.util;
+
+/**
+* @author: Chenzhenyong
+* @description: 格式化操作类
+* @date: Created in 12:08 2018/7/24
+*/
+public class ByteFormat {
+    private static final char[] HEX = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+    public ByteFormat() {
+    }
+
+    public static final String bytesToHexString(byte[] bArray) {
+        StringBuffer sb = new StringBuffer(bArray.length);
+
+        for (int i = 0; i < bArray.length; ++i) {
+            String sTemp = Integer.toHexString(255 & bArray[i]);
+            if (sTemp.length() < 2) {
+                sb.append(0);
+            }
+
+            sb.append(sTemp.toUpperCase());
+        }
+
+        return sb.toString();
+    }
+
+    public static byte[] hexToBytes(String str) {
+        if (str == null) {
+            return null;
+        } else {
+            char[] hex = str.toCharArray();
+            int length = hex.length / 2;
+            byte[] raw = new byte[length];
+
+            for (int i = 0; i < length; ++i) {
+                int high = Character.digit(hex[i * 2], 16);
+                int low = Character.digit(hex[i * 2 + 1], 16);
+                int value = high << 4 | low;
+                if (value > 127) {
+                    value -= 256;
+                }
+
+                raw[i] = (byte) value;
+            }
+
+            return raw;
+        }
+    }
+}

+ 55 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/util/CtwingBase64Utils.java

@@ -0,0 +1,55 @@
+package com.sptg.permissions.api.thirdauth.util;
+
+import sun.misc.BASE64Decoder;
+import sun.misc.BASE64Encoder;
+
+/** *//**
+ * <p>
+ * BASE64编码解码工具包
+ * </p>
+ * <p>
+ * 依赖javabase64-1.3.1.jar
+ * </p>
+ *
+ * @author IceWee
+ * @date 2012-5-19
+ * @version 1.0
+ */
+public class CtwingBase64Utils {
+
+/** *//**
+     * 文件读取缓冲区大小
+     */
+    private static final int CACHE_SIZE = 1024;
+
+/**
+     * <p>
+     * BASE64字符串解码为二进制数据
+     * </p>
+     *
+     * @param base64
+     * @return
+     * @throws Exception
+     */
+    public static byte[] decode(String base64) throws Exception {
+        BASE64Decoder base64Decoder = new BASE64Decoder();
+        byte[] buffer = base64Decoder.decodeBuffer(base64);
+        return buffer;
+    }
+
+/**
+     * <p>
+     * 二进制数据编码为BASE64字符串
+     * </p>
+     *
+     * @param bytes
+     * @return
+     * @throws Exception
+     */
+    public static String encode(byte[] bytes) throws Exception {
+        BASE64Encoder base64Encoder = new BASE64Encoder();
+        return base64Encoder.encodeBuffer(bytes);
+    }
+
+
+}

+ 316 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/util/CtwingRSAUtils.java

@@ -0,0 +1,316 @@
+package com.sptg.permissions.api.thirdauth.util;
+
+import com.sptg.permissions.api.thirdauth.constants.CtwingAuthConstants;
+import sun.misc.BASE64Decoder;
+
+import java.io.ByteArrayOutputStream;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.crypto.Cipher;
+
+/**
+* @author: 罗纳德·李维斯特(Ron [R]ivest)、阿迪·萨莫尔(Adi [S]hamir)和伦纳德·阿德曼(Leonard [A]dleman)
+* @description:
+ * RSA公钥/私钥/签名工具包
+ * 字符串格式的密钥在未在特殊说明情况下都为BASE64编码格式
+ * 由于非对称加密速度极其缓慢,一般文件不使用它来加密而是使用对称加密,<br/>
+ * 非对称加密算法可以用来对对称加密的密钥加密,这样保证密钥的安全也就保证了数据的安全
+* @date: Created in 11:20 2018/8/20
+*/
+public class CtwingRSAUtils {
+
+    /**
+     * 加密算法RSA
+     */
+    public static final String KEY_ALGORITHM = "RSA";
+
+    /**
+     * 签名算法
+     */
+    public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
+
+    /**
+     * 获取公钥的key
+     */
+    private static final String PUBLIC_KEY = "RSAPublicKey";
+
+    /**
+     * 获取私钥的key
+     */
+    private static final String PRIVATE_KEY = "RSAPrivateKey";
+
+    /**
+     * RSA最大加密明文大小
+     */
+    private static final int MAX_ENCRYPT_BLOCK = 117;
+
+    /**
+     * RSA最大解密密文大小
+     */
+    private static final int MAX_DECRYPT_BLOCK = 128;
+
+    /**
+     * 生成密钥对(公钥和私钥)
+     *
+     * @return
+     * @throws Exception
+     */
+    public static Map<String, Object> genKeyPair() throws Exception {
+        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
+        keyPairGen.initialize(1024);
+        KeyPair keyPair = keyPairGen.generateKeyPair();
+        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
+        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
+        Map<String, Object> keyMap = new HashMap<String, Object>(2);
+        keyMap.put(PUBLIC_KEY, publicKey);
+        keyMap.put(PRIVATE_KEY, privateKey);
+        return keyMap;
+    }
+
+    /**
+     * 用私钥对信息生成数字签名
+     *
+     * @param content       已加密数据
+     * @param privateKey 私钥(BASE64编码)
+     * @return
+     * @throws Exception
+     */
+    public static String sign(String content, String privateKey) throws Exception {
+        byte[] data = content.getBytes();
+        byte[] keyBytes = new BASE64Decoder().decodeBuffer(privateKey);
+        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
+        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
+        PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
+        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
+        signature.initSign(privateK);
+        signature.update(data);
+//        return Base64Utils.encode(signature.sign());
+        return ByteFormat.bytesToHexString(signature.sign());
+    }
+
+    /**
+     * 校验数字签名
+     *
+     * @param content      源数据
+     * @param publicKey 公钥(BASE64编码)
+     * @param sign      数字签名
+     * @return
+     * @throws Exception
+     */
+    public static boolean verify(String content, String publicKey, String sign)
+            throws Exception {
+        byte[] data = content.getBytes();
+        byte[] keyBytes = new BASE64Decoder().decodeBuffer(publicKey);
+        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
+        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
+        PublicKey publicK = keyFactory.generatePublic(keySpec);
+        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
+        signature.initVerify(publicK);
+        signature.update(data);
+//        return signature.verify(new BASE64Decoder().decodeBuffer(sign));
+        return signature.verify(ByteFormat.hexToBytes(sign));
+    }
+
+    /**
+     * 私钥解密
+     *
+     * @param encryptedStr 已加密数据
+     * @param privateKey    私钥(BASE64编码)
+     * @return
+     * @throws Exception
+     */
+    public static String decryptByPrivateKeyForLongStr(String encryptedStr, String privateKey)
+            throws Exception {
+        byte[] encryptedData = ByteFormat.hexToBytes(encryptedStr);
+        byte[] keyBytes = new BASE64Decoder().decodeBuffer(privateKey);
+        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
+        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
+        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
+        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
+        cipher.init(Cipher.DECRYPT_MODE, privateK);
+        int inputLen = encryptedData.length;
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        int offSet = 0;
+        byte[] cache;
+        int i = 0;
+        // 对数据分段解密
+        while (inputLen - offSet > 0) {
+            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
+                cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
+            } else {
+                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
+            }
+            out.write(cache, 0, cache.length);
+            i++;
+            offSet = i * MAX_DECRYPT_BLOCK;
+        }
+        byte[] decryptedData = out.toByteArray();
+        out.close();
+        return new String(decryptedData);
+    }
+
+    /**
+     * 公钥解密
+     *
+     * @param encryptedData 已加密数据
+     * @param publicKey     公钥(BASE64编码)
+     * @return
+     * @throws Exception
+     */
+    public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey)
+            throws Exception {
+        byte[] keyBytes = new BASE64Decoder().decodeBuffer(publicKey);
+        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
+        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
+        Key publicK = keyFactory.generatePublic(x509KeySpec);
+        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
+        cipher.init(Cipher.DECRYPT_MODE, publicK);
+        int inputLen = encryptedData.length;
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        int offSet = 0;
+        byte[] cache;
+        int i = 0;
+        // 对数据分段解密
+        while (inputLen - offSet > 0) {
+            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
+                cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
+            } else {
+                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
+            }
+            out.write(cache, 0, cache.length);
+            i++;
+            offSet = i * MAX_DECRYPT_BLOCK;
+        }
+        byte[] decryptedData = out.toByteArray();
+        out.close();
+        return decryptedData;
+    }
+
+    /**
+     * 公钥加密(数据比较长时,需要使用这个方法)
+     *
+     * @param content   源数据
+     * @param publicKey 公钥(BASE64编码)
+     * @return
+     * @throws Exception
+     */
+    public static String encryptByPublicKeyForLongStr(String content, String publicKey)
+            throws Exception {
+        byte[] keyBytes = new BASE64Decoder().decodeBuffer(publicKey);
+        byte[] data = content.getBytes();
+        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
+        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
+        Key publicK = keyFactory.generatePublic(x509KeySpec);
+        // 对数据加密
+        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
+        cipher.init(Cipher.ENCRYPT_MODE, publicK);
+        int inputLen = data.length;
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        int offSet = 0;
+        byte[] cache;
+        int i = 0;
+        // 对数据分段加密
+        while (inputLen - offSet > 0) {
+            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
+                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
+            } else {
+                cache = cipher.doFinal(data, offSet, inputLen - offSet);
+            }
+            out.write(cache, 0, cache.length);
+            i++;
+            offSet = i * MAX_ENCRYPT_BLOCK;
+        }
+        byte[] encryptedData = out.toByteArray();
+        out.close();
+        return ByteFormat.bytesToHexString(encryptedData);
+    }
+
+    /**
+     * 私钥加密
+     *
+     * @param data       源数据
+     * @param privateKey 私钥(BASE64编码)
+     * @return
+     * @throws Exception
+     */
+    public static byte[] encryptByPrivateKey(byte[] data, String privateKey)
+            throws Exception {
+        byte[] keyBytes = new BASE64Decoder().decodeBuffer(privateKey);
+        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
+        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
+        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
+        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
+        cipher.init(Cipher.ENCRYPT_MODE, privateK);
+        int inputLen = data.length;
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        int offSet = 0;
+        byte[] cache;
+        int i = 0;
+        // 对数据分段加密
+        while (inputLen - offSet > 0) {
+            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
+                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
+            } else {
+                cache = cipher.doFinal(data, offSet, inputLen - offSet);
+            }
+            out.write(cache, 0, cache.length);
+            i++;
+            offSet = i * MAX_ENCRYPT_BLOCK;
+        }
+        byte[] encryptedData = out.toByteArray();
+        out.close();
+        return encryptedData;
+    }
+
+    /**
+     * 获取私钥
+     *
+     * @param keyMap 密钥对
+     * @return
+     * @throws Exception
+     */
+    public static String getPrivateKey(Map<String, Object> keyMap)
+            throws Exception {
+        Key key = (Key) keyMap.get(PRIVATE_KEY);
+        return CtwingBase64Utils.encode(key.getEncoded());
+    }
+
+    /**
+     * 获取公钥
+     *
+     * @param keyMap 密钥对
+     * @return
+     * @throws Exception
+     */
+    public static String getPublicKey(Map<String, Object> keyMap)
+            throws Exception {
+        Key key = (Key) keyMap.get(PUBLIC_KEY);
+        return CtwingBase64Utils.encode(key.getEncoded());
+    }
+
+//    public static void main (String[] args) throws Exception {
+//        String msg = "{\"result\":0,\"msg\":\"操作成功\",\"email\":\"\",\"operator\":\"中国移动\"}";
+//        String encStr = encryptByPublicKeyForLongStr(msg, CtwingAuthConstants.PUB_KEY);
+//        System.out.println(encStr);
+//
+//        encStr =
+//                "7DFE349C22FAC96619C7A80D9F07CC35D968D28F546FB39CAC71DAA71ABBF303C6AFDB5C56BB2F48F3D522EB76CADBAC3939FEAAA298C792510245EBF9137898605765C532AF7B4298A4A21EC96E9D292ED7662A26BFF9723C5BDD2F5976D20B0A09F5AA77DE1EE383E0D377F86A888463AB0A7CCB4A2C8599E83F62495EA94B13813D15FAA8DCCD0EFEC91076AEDCA8A05613D8639F11E9DAC0C85ABB473AB1FD27F3D70921ADD479B50537F8BC17048D497E77B775711DA60B2DC08CBE8ED3279429EAFFAC2107F742BD4D08D4CEB204D4725B7E11107DA177D27CCD6EA7BA817485B678DC786A00758828BF72230B0801DEE3A99E696B6A2E507FDC708AA44C58EDB909D6AA7FF2B1218C51C24047D96F25E4C03724C90F6EEEE8E49B14B25DCE431D0ECA7D115F65B2A135972D9AEB6BF0DF7EBEDF391B82F0C8F0355EC16090AF88333AA31B0210E3652015DF839A187AC0CFDA709119FD5C80D2710FC38BE265974F22E0E35AE375B32BA05029F4196C9BEF845312C04AD04359132BC8";
+//        String decStr = decryptByPrivateKeyForLongStr(encStr, CtwingAuthConstants.PRI_KEY);
+//        System.out.println(new String(decStr));
+//
+//    }
+
+}
+

+ 90 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/util/CtwingRequestUtil.java

@@ -0,0 +1,90 @@
+package com.sptg.permissions.api.thirdauth.util;
+
+
+import java.security.interfaces.RSAPrivateKey;
+import java.util.*;
+import java.util.Map.Entry;
+
+/**
+* @author: Chenzhenyong
+* @description: 请求工具类
+* @date: Created in 18:53 2018/5/8
+*/
+public class CtwingRequestUtil {
+
+    /**
+     * 生成签名串
+     * @param requestData 除sign外的通用参数
+     * @param privateKey rsa私钥
+     * @return
+     */
+    public static String generateSign(Map<String, String> requestData, String privateKey) throws Exception {
+        RSAPrivateKey rsaPrivateKey = RSAUtil.loadPrivateKey(privateKey);
+        return generateSign(requestData, rsaPrivateKey);
+    }
+
+    /**
+     * 生成签名串 所有参数按key的升序排序
+     * @param requestData 除sign外的通用参数
+     * @param rsaPrivateKey RSA私钥
+     * @return
+     * @throws Exception
+     */
+    public static String generateSign(Map<String, String> requestData, RSAPrivateKey rsaPrivateKey) throws Exception {
+        /*List<Entry<String, String>> requestDataList = new ArrayList<>(requestData.entrySet());
+        Collections.sort(requestDataList, Comparator.comparing(Entry::getKey));
+        String encryptValue = "";
+        for(Entry<String, String> entry : requestDataList){
+            encryptValue = encryptValue + entry.getValue();
+        }*/
+        return RSAUtil.sign(generatePlainText(requestData), rsaPrivateKey);
+    }
+
+    /**
+     * 参数排序
+     * @param returnData
+     * @return
+     */
+    private static String generatePlainText(Map<String,String> returnData){
+        //排序参数
+        List<Entry<String,String>> mappingList = null;
+        mappingList = new ArrayList<Entry<String,String>>(returnData.entrySet());
+        Collections.sort(mappingList,new Comparator<Entry<String,String>>(){public int compare(
+                Entry<String,String> mapping1,
+                Entry<String,String> mapping2){
+            return mapping1.getKey().compareTo(mapping2.getKey());
+        }
+        });
+
+        String plainText="";
+        for(Entry<String,String> mapping:mappingList){
+            plainText+=mapping.getValue();
+        }
+        return plainText;
+    }
+
+
+    /**
+     * 生成params参数
+     * @param requestData 业务参数
+     * @param appSecret 应用秘钥
+     * @return
+     */
+    public static String generateParams(Map<String, String> requestData, String appSecret) throws Exception {
+        StringBuffer sb = new StringBuffer();
+//        requestData.forEach((k, v) -> sb.append(k).append("=").append(v).append("&"));
+        for(Entry<String, String> entry : requestData.entrySet()) {
+            sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
+        }
+        byte[] encValue = XXTeaUtil.encrypt(sb.toString().getBytes("UTF-8"), appSecret.getBytes("UTF-8"));
+        return ByteFormat.bytesToHexString(encValue);
+    }
+
+//    public static void main(String[] args) throws Exception {
+//        String params =
+//                "9FBCFC97786BBF8404E12E4BDFAA86A5EA250BF22DACBDC44E385324210249220954E63F8DEB39E561D63826F95CA940EB7DA451";
+//        byte[] result = XXTeaUtil.decrypt(ByteFormat.hexToBytes(params),
+//                "C16bkftbCzGuiUwNj10Q0NbZH4NKa7Vz".getBytes("UTF-8"));
+//        System.out.println(new String(result));
+//    }
+}

+ 306 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/util/HmacSha1Util.java

@@ -0,0 +1,306 @@
+package com.sptg.permissions.api.thirdauth.util;
+
+import java.util.Locale;
+
+/**
+* @author: Chenzhenyong
+* @description: HMAC_SHA1算法工具类
+* @date: Created in 10:52 2018/8/23
+*/
+public class HmacSha1Util {
+    private final int[] abcde = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 };
+    /**
+     * 摘要数据存储数组
+     */
+    private int[] digestInt = new int[5];
+    /**
+     * 计算过程中的临时数据存储数组
+     */
+    private int[] tmpData = new int[80];
+
+    /**
+     * 计算sha-1摘要
+     * @param byteData
+     * @return
+     */
+    private int process_input_bytes(byte[] byteData) {
+        // 初试化常量
+        System.arraycopy(abcde, 0, digestInt, 0, abcde.length);
+        // 格式化输入字节数组,补10及长度数据
+        byte[] newbyte = byteArrayFormatData(byteData);
+        // 获取数据摘要计算的数据单元个数
+        int MCount = newbyte.length / 64;
+        // 循环对每个数据单元进行摘要计算
+        for (int pos = 0; pos < MCount; pos++) {
+            // 将每个单元的数据转换成16个整型数据,并保存到tmpData的前16个数组元素中
+            for (int j = 0; j < 16; j++) {
+                tmpData[j] = byteArrayToInt(newbyte, (pos * 64) + (j * 4));
+            }
+            // 摘要计算函数
+            encrypt();
+        }
+        return 20;
+    }
+
+    /**
+     * 格式化输入字节数组格式
+     * @param byteData
+     * @return
+     */
+    private byte[] byteArrayFormatData(byte[] byteData) {
+        // 补0数量
+        int zeros ;  //int zeros = 0 ;  sonar
+        // 补位后总位数
+        int size  ;  // int size = 0 ;  sonar
+        // 原始数据长度
+        int n = byteData.length;
+        // 模64后的剩余位数
+        int m = n % 64;
+        // 计算添加0的个数以及添加10后的总长度
+        if (m < 56) {
+            zeros = 55 - m;
+            size = n - m + 64;
+        } else if (m == 56) {
+            zeros = 63;
+            size = n + 8 + 64;
+        } else {
+            zeros = 63 - m + 56;
+            size = (n + 64) - m + 64;
+        }
+        // 补位后生成的新数组内容
+        byte[] newbyte = new byte[size];
+        // 复制数组的前面部分
+        System.arraycopy(byteData, 0, newbyte, 0, n);
+        // 获得数组Append数据元素的位置
+        int l = n;
+        // 补1操作
+        newbyte[l++] = (byte) 0x80;
+        // 补0操作
+        for (int i = 0; i < zeros; i++) {
+            newbyte[l++] = (byte) 0x00;
+        }
+        // 计算数据长度,补数据长度位共8字节,长整型
+        long n1 = (long) n * 8;
+        byte h8 = (byte) (n1 & 0xFF);
+        byte h7 = (byte) ((n1 >> 8) & 0xFF);
+        byte h6 = (byte) ((n1 >> 16) & 0xFF);
+        byte h5 = (byte) ((n1 >> 24) & 0xFF);
+        byte h4 = (byte) ((n1 >> 32) & 0xFF);
+        byte h3 = (byte) ((n1 >> 40) & 0xFF);
+        byte h2 = (byte) ((n1 >> 48) & 0xFF);
+        byte h1 = (byte) (n1 >> 56);
+        newbyte[l++] = h1;
+        newbyte[l++] = h2;
+        newbyte[l++] = h3;
+        newbyte[l++] = h4;
+        newbyte[l++] = h5;
+        newbyte[l++] = h6;
+        newbyte[l++] = h7;
+        newbyte[l] = h8;
+        return newbyte;
+    }
+
+    private int f1(int x, int y, int z) {
+        return (x & y) | (~x & z);
+    }
+
+    private int f2(int x, int y, int z) {
+        return x ^ y ^ z;
+    }
+
+    private int f3(int x, int y, int z) {
+        return (x & y) | (x & z) | (y & z);
+    }
+
+    private int f4(int x, int y) {
+        return (x << y) | x >>> (32 - y);
+    }
+
+    /**
+     * 单元摘要计算函数
+     */
+    private void encrypt() {
+        for (int i = 16; i <= 79; i++) {
+            tmpData[i] = f4(tmpData[i - 3] ^ tmpData[i - 8] ^ tmpData[i - 14] ^
+                    tmpData[i - 16], 1);
+        }
+        int[] tmpabcde = new int[5];
+        for (int i1 = 0; i1 < tmpabcde.length; i1++) {
+            tmpabcde[i1] = digestInt[i1];
+        }
+        for (int j = 0; j <= 19; j++) {
+            int tmp = f4(tmpabcde[0], 5) +
+                f1(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] +
+                tmpData[j] + 0x5a827999;
+            tmpabcde[4] = tmpabcde[3];
+            tmpabcde[3] = tmpabcde[2];
+            tmpabcde[2] = f4(tmpabcde[1], 30);
+            tmpabcde[1] = tmpabcde[0];
+            tmpabcde[0] = tmp;
+        }
+        for (int k = 20; k <= 39; k++) {
+            int tmp = f4(tmpabcde[0], 5) +
+                f2(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] +
+                tmpData[k] + 0x6ed9eba1;
+            tmpabcde[4] = tmpabcde[3];
+            tmpabcde[3] = tmpabcde[2];
+            tmpabcde[2] = f4(tmpabcde[1], 30);
+            tmpabcde[1] = tmpabcde[0];
+            tmpabcde[0] = tmp;
+        }
+        for (int l = 40; l <= 59; l++) {
+            int tmp = f4(tmpabcde[0], 5) +
+                f3(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] +
+                tmpData[l] + 0x8f1bbcdc;
+            tmpabcde[4] = tmpabcde[3];
+            tmpabcde[3] = tmpabcde[2];
+            tmpabcde[2] = f4(tmpabcde[1], 30);
+            tmpabcde[1] = tmpabcde[0];
+            tmpabcde[0] = tmp;
+        }
+        for (int m = 60; m <= 79; m++) {
+            int tmp = f4(tmpabcde[0], 5) +
+                f2(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] +
+                tmpData[m] + 0xca62c1d6;
+            tmpabcde[4] = tmpabcde[3];
+            tmpabcde[3] = tmpabcde[2];
+            tmpabcde[2] = f4(tmpabcde[1], 30);
+            tmpabcde[1] = tmpabcde[0];
+            tmpabcde[0] = tmp;
+        }
+        for (int i2 = 0; i2 < tmpabcde.length; i2++) {
+            digestInt[i2] = digestInt[i2] + tmpabcde[i2];
+        }
+        for (int n = 0; n < tmpData.length; n++) {
+            tmpData[n] = 0;
+        }
+    }
+
+    /**
+     * 4字节数组转换为整数
+     * @param bytedata
+     * @param i
+     * @return
+     */
+    private int byteArrayToInt(byte[] bytedata, int i) {
+        return ((bytedata[i] & 0xff) << 24) | ((bytedata[i + 1] & 0xff) << 16) |
+        ((bytedata[i + 2] & 0xff) << 8) | (bytedata[i + 3] & 0xff);
+    }
+
+    /**
+     * 整数转换为4字节数组
+     * @param intValue
+     * @param byteData
+     * @param i
+     */
+    private void intToByteArray(int intValue, byte[] byteData, int i) {
+        byteData[i] = (byte) (intValue >>> 24);
+        byteData[i + 1] = (byte) (intValue >>> 16);
+        byteData[i + 2] = (byte) (intValue >>> 8);
+        byteData[i + 3] = (byte) intValue;
+    }
+
+    /**
+     * 计算sha-1摘要,返回相应的字节数组
+     * @param byteData
+     * @return
+     */
+    public byte[] getDigestOfBytes(byte[] byteData) {
+        process_input_bytes(byteData);
+        byte[] digest = new byte[20];
+        for (int i = 0; i < digestInt.length; i++) {
+            intToByteArray(digestInt[i], digest, i * 4);
+        }
+        return digest;
+    }
+
+    /**
+     *
+     * @param data
+     * @param key
+     * @return
+     */
+	public static byte[] getHmacSHA1(String data, String key){
+		if (StringUtil.isEmpty(key)) {
+			return null;
+		}
+        byte[] ipadArray = new byte[64];
+        byte[] opadArray = new byte[64];
+        byte[] keyArray = new byte[64];
+        int ex = key.length();
+        HmacSha1Util sha1= new HmacSha1Util();
+        if (key.length() > 64) {
+            byte[] temp = sha1.getDigestOfBytes(StringUtil.getBytes(key));     //sonar key.getBytes()
+            ex = temp.length;
+            for (int i = 0; i < ex; i++) {
+                keyArray[i] = temp[i];
+            }
+        }else{
+            byte[] temp = StringUtil.getBytes(key);     //sonar key.getBytes()
+            for (int i = 0; i < temp.length; i++) {
+                keyArray[i] = temp[i];
+            }
+        }
+        for (int i = ex; i < 64; i++) {
+            keyArray[i] = 0;
+        }
+        for (int j = 0; j < 64; j++) {
+            ipadArray[j] = (byte) (keyArray[j] ^ 0x36);
+            opadArray[j] = (byte) (keyArray[j] ^ 0x5C);
+        }
+        byte[] tempResult = sha1.getDigestOfBytes(join(ipadArray, StringUtil.getBytes(data)));   //sonar data.getBytes()
+        return sha1.getDigestOfBytes(join(opadArray,tempResult));
+    }
+
+    /**
+     *
+     * @param b1
+     * @param b2
+     * @return
+     */
+    private static byte[] join(byte[] b1,byte[] b2){
+        int length = b1.length + b2.length;
+        byte[] newer = new byte[length];
+        for (int i = 0; i < b1.length; i++) {
+            newer[i] = b1[i];
+        }
+        for (int i = 0; i < b2.length; i++) {
+            newer[i+b1.length] = b2[i];
+        }
+        return newer;
+    }
+
+    /**
+     *
+     * @param src
+     * @return
+     */
+	public static String bytesToHexString(byte[] src){
+		StringBuilder stringBuilder = new StringBuilder("");
+		if (src == null || src.length <= 0) {  
+			return null;  
+		}  
+		for (int i = 0; i < src.length; i++) {  
+			int v = src[i] & 0xFF;  
+			String hv = Integer.toHexString(v).toUpperCase(Locale.CHINA);   //sonar Define the locale to be used in this String operation.
+			if (hv.length() < 2) {  
+				stringBuilder.append(0);  
+			}  
+			stringBuilder.append(hv);  
+		}  
+		return stringBuilder.toString();  
+	}
+
+    public static void main(String[] args) {
+	    //原字符串
+        String str = "zhpt_inner_test1jsonA07F8458AC429D517E13DA47E180E2A57495B89B34E3A48B697C72FBEE864E43135C121877B2D873A5B74ABAEF5693B7842BA5D474810D3A99EADEA0EFBD0FED5F63E3DC0811C3FE114F4876ABFE38C3414653E6206E22A2ECFD1E60BF8C2698EF7A91F542126B173C9601BDB37EF10ADE3876AFC0313F38CEDC0CA3E5A666EEv1.5";
+        //秘钥
+        String secret = "sAecMFcAlIXes93VaWXgr3jgMup4Y0a6";
+
+        //加密
+        byte[] result = getHmacSHA1(str,secret);
+        System.out.println("原字符串"+str);
+        System.out.println("加密后字符串"+bytesToHexString(result));
+    }
+
+}

+ 220 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/util/RSAUtil.java

@@ -0,0 +1,220 @@
+package com.sptg.permissions.api.thirdauth.util;
+
+import sun.misc.BASE64Decoder;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.*;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+/**
+* @author: Chenzhenyong
+* @description: RSA工具类
+* @date: Created in 10:59 2018/7/24
+*/
+public class RSAUtil {
+
+    private static final String DEFAULT_CHARSET = "UTF-8";
+    private static final String RSA_ALGORITHM = "RSA";
+    private static final String SIGNATURE_ALGORITHM = "SHA1WithRSA";
+    private static final String RSA_ALGORITHM_PADDING = "RSA/ECB/PKCS1Padding";
+
+    private static final String NO_SUCH_ALGORITHM_EXCEPTION_MSG = "No such algorithm";
+    private static final String INVALID_KEY_SPEC_EXCEPTION_MSG = "Invalid key spec";
+    private static final String IO_EXCEPTION_MSG = "Reading key data error";
+    private static final String NO_SUCH_PADDING_EXCEPTION_MSG = "No such padding";
+    private static final String NULL_POINTER_EXCEPTION_MSG = "No key data found";
+    private static final String INVALID_KEY_EXCEPTION_MSG = "Invalid key";
+    private static final String ILLEGAL_BLOCK_SIZE_EXCEPTION_MSG = "Illegal block size";
+    private static final String BAD_PADDING_EXCEPTION_MSG = "Bad padding";
+    private static final String SIGNATURE_EXCEPTION_MSG = "Signature exception";
+    private static final String UnsupportedEncodingExceptionMsg = "Unsupported encoding";
+
+    /**
+     * 从字符串中加载公钥
+     *
+     * @param publicKeyStr 公钥数据字符串
+     * @throws Exception 加载公钥时产生的异常
+     */
+    public static RSAPublicKey loadPublicKey(String publicKeyStr) throws Exception {
+        RSAPublicKey publicKey;
+        try {
+            BASE64Decoder base64Decoder = new BASE64Decoder();
+            byte[] buffer = base64Decoder.decodeBuffer(publicKeyStr);
+            KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
+            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
+            publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
+        } catch (NoSuchAlgorithmException e) {
+            throw new NoSuchAlgorithmException(NO_SUCH_ALGORITHM_EXCEPTION_MSG);
+        } catch (InvalidKeySpecException e) {
+            throw new InvalidKeySpecException(INVALID_KEY_SPEC_EXCEPTION_MSG);
+        } catch (IOException e) {
+            throw new IOException(IO_EXCEPTION_MSG);
+        } catch (NullPointerException e) {
+            throw new NullPointerException(NULL_POINTER_EXCEPTION_MSG);
+        }
+        return publicKey;
+    }
+
+    /**
+     * 加载私钥
+     * @param privateKeyStr
+     * @return
+     * @throws Exception
+     */
+    public static RSAPrivateKey loadPrivateKey(String privateKeyStr) throws Exception {
+        RSAPrivateKey privateKey;
+        try {
+            BASE64Decoder base64Decoder = new BASE64Decoder();
+            byte[] buffer = base64Decoder.decodeBuffer(privateKeyStr);
+            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
+            KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
+            privateKey = (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
+        } catch (NoSuchAlgorithmException e) {
+            throw new NoSuchAlgorithmException(NO_SUCH_ALGORITHM_EXCEPTION_MSG);
+        } catch (InvalidKeySpecException e) {
+            throw new InvalidKeySpecException(INVALID_KEY_SPEC_EXCEPTION_MSG);
+        } catch (IOException e) {
+            throw new IOException(IO_EXCEPTION_MSG);
+        } catch (NullPointerException e) {
+            throw new NullPointerException(NULL_POINTER_EXCEPTION_MSG);
+        }
+        return privateKey;
+    }
+
+    /**
+     * 加密过程
+     *
+     * @param publicKey 公钥
+     * @param content   明文数据
+     * @return
+     * @throws Exception 加密过程中的异常信息
+     */
+    public static String encrypt(RSAPublicKey publicKey, String content) throws Exception {
+        byte[] plainTextData = content.getBytes();
+        Cipher cipher;
+        try {
+            cipher = Cipher.getInstance(RSA_ALGORITHM_PADDING);
+            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
+            byte[] output = cipher.doFinal(plainTextData);
+            return ByteFormat.bytesToHexString(output);
+        } catch (NoSuchAlgorithmException e) {
+            throw new NoSuchAlgorithmException(NO_SUCH_ALGORITHM_EXCEPTION_MSG);
+        } catch (NoSuchPaddingException e) {
+            throw new NoSuchPaddingException(NO_SUCH_PADDING_EXCEPTION_MSG);
+        } catch (InvalidKeyException e) {
+            throw new InvalidKeyException(INVALID_KEY_EXCEPTION_MSG);
+        } catch (IllegalBlockSizeException e) {
+            throw new IllegalBlockSizeException(ILLEGAL_BLOCK_SIZE_EXCEPTION_MSG);
+        } catch (BadPaddingException e) {
+            throw new BadPaddingException(BAD_PADDING_EXCEPTION_MSG);
+        }
+    }
+
+    /**
+     * 解密过程
+     *
+     * @param privateKey 私钥
+     * @param content    密文数据
+     * @return 明文
+     * @throws Exception 解密过程中的异常信息
+     */
+    public static String decrypt(RSAPrivateKey privateKey, String content) throws Exception {
+        byte[] cipherData = ByteFormat.hexToBytes(content);
+        Cipher cipher;
+        try {
+            cipher = Cipher.getInstance(RSA_ALGORITHM_PADDING);
+            cipher.init(Cipher.DECRYPT_MODE, privateKey);
+            byte[] output = cipher.doFinal(cipherData);
+            return new String(output);
+        } catch (NoSuchAlgorithmException e) {
+            throw new NoSuchAlgorithmException(NO_SUCH_ALGORITHM_EXCEPTION_MSG);
+        } catch (NoSuchPaddingException e) {
+            throw new NoSuchPaddingException(NO_SUCH_PADDING_EXCEPTION_MSG);
+        } catch (InvalidKeyException e) {
+            throw new InvalidKeyException(INVALID_KEY_EXCEPTION_MSG);
+        } catch (IllegalBlockSizeException e) {
+            throw new IllegalBlockSizeException(ILLEGAL_BLOCK_SIZE_EXCEPTION_MSG);
+        } catch (BadPaddingException e) {
+            throw new BadPaddingException(BAD_PADDING_EXCEPTION_MSG);
+        }
+    }
+
+    /**
+     * RSA签名
+     * @param content 待签名数据
+     * @param privateKey 私钥
+     * @return 签名值
+     */
+    public static String sign(String content, PrivateKey privateKey) throws Exception {
+        try {
+            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
+            signature.initSign(privateKey);
+            signature.update(content.getBytes(DEFAULT_CHARSET));
+            byte[] signed = signature.sign();
+            return ByteFormat.bytesToHexString(signed);
+        } catch (NoSuchAlgorithmException e) {
+            throw new NoSuchAlgorithmException(NO_SUCH_ALGORITHM_EXCEPTION_MSG);
+        } catch (InvalidKeyException e) {
+            throw  new InvalidKeyException(INVALID_KEY_EXCEPTION_MSG);
+        } catch (SignatureException e) {
+            throw new SignatureException(SIGNATURE_EXCEPTION_MSG);
+        } catch (UnsupportedEncodingException e) {
+            throw new UnsupportedEncodingException(UnsupportedEncodingExceptionMsg);
+        }
+    }
+
+    /**
+     * RSA验签
+     * @param content 待签名数据
+     * @param sign 签名值
+     * @param publicKey 分配给开发商公钥
+     * @return 布尔值
+     */
+    public static boolean verifySign(String content, String sign, PublicKey publicKey) throws Exception {
+        try {
+            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
+            signature.initVerify(publicKey);
+            signature.update( content.getBytes(DEFAULT_CHARSET) );
+            return signature.verify(ByteFormat.hexToBytes(sign));
+        } catch (NoSuchAlgorithmException e) {
+            throw new NoSuchAlgorithmException(NO_SUCH_ALGORITHM_EXCEPTION_MSG);
+        } catch (InvalidKeyException e) {
+            throw  new InvalidKeyException(INVALID_KEY_EXCEPTION_MSG);
+        } catch (SignatureException e) {
+            throw new SignatureException(SIGNATURE_EXCEPTION_MSG);
+        } catch (UnsupportedEncodingException e) {
+            throw new UnsupportedEncodingException(UnsupportedEncodingExceptionMsg);
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        String publicKeyStr = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvC7WWvgcvpFmybFTHlCpWQvh7rpzatimcOFiGJ3OzCPz/YF0LWugr/46ub0Bdh5Cq/cb5ZmOJiA0KEK5QdM2V8/k4wtJeYl7wnwoEolXp5Swqs/hdYb/YOINRFFgHsbnrV3AY4S2x37ztJL0UrEWEONmlcWKLN4Srv89VGKgvJwIDAQAB";
+        String privateKeyStr = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAK8LtZa+By+kWbJsVMeUKlZC" +
+                "+HuunNq2KZw4WIYnc7MI/P9gXQta6Cv/jq5vQF2HkKr9xvlmY4mIDQoQrlB0zZXz+TjC0l5iXvCfCgSiVenlLCqz+F1hv9g4g1EUWAexuetXcBjhLbHfvO0kvRSsRYQ42aVxYos3hKu/z1UYqC8nAgMBAAECgYBEsE6YkYcWXeLIzhPSoUSfxvXk6tcoR/U6FS4/rnmLVsqYl8LLMugKY+UkdAmI6iqNvrn2ogQLMvUS7wrIDZ2iRLdU5yiNfqMSlG2kPK2lMYa0GEQGH9xF6KwI/yJ+WtjIjPxCAFFUrRi1aCJlCNT/yav3j82g6uovG3ciTo6GeQJBAOHZfn5lCCKnF3iZX6BhH6C7CFYhTRdetJKfrGZqlj4tRbJDou54OjHe/eGT+o8xlrgu7PZFmnLu/I5ve36GvU0CQQDGafjbOS3DFQUvFA0ULJOQzdCAQvdx/AYQUsdW3EvwfK0S1ZuZqZoOykT7biy00vBF8pwXy4kL6GBOkY4cNTRDAkEAvYi/3iS9gg9F5ECafsZjO4kaguWpg55H3fDARqbWdVGa9vJKDuS4udeQqjl8gaU0/lbrJ/Xbmu6y5nnqYpGC1QJAfRWp0WrGssm5ruhRJnrDvPJDk9ij7rQXjorhKJ1RMpcm9Uy8/66wdMqHmormnEivOSmtxkKGb39b16xjjtzryQJAJEnDgK97Ktq1lGR/Nx7nwE6Uikvxc0V/UgAuJdB6Hj53hVWHwmoIpyillJvNfZNnNLEQxikglSIUpBQ++p0VqQ==";
+
+        //平台使用合作方公钥加密
+        String msg = "{\"email\":\"\",\"operator\":\"中国移动\"}";
+        String encStr = RSAUtil.encrypt(RSAUtil.loadPublicKey(publicKeyStr), msg);
+        System.out.println(encStr);
+
+        //合作方使用自己私钥解密
+        String decStr = RSAUtil.decrypt(RSAUtil.loadPrivateKey(privateKeyStr), encStr);
+        System.out.println(decStr);
+
+        //合作方使用自己私钥签名
+        String signStr = sign(msg, loadPrivateKey(privateKeyStr));
+        System.out.println(signStr);
+
+        //平台使用合作方公钥验签
+        System.out.println(verifySign(msg, signStr, loadPublicKey(publicKeyStr)));
+    }
+}

+ 66 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/util/StringUtil.java

@@ -0,0 +1,66 @@
+package com.sptg.permissions.api.thirdauth.util;
+
+import java.io.UnsupportedEncodingException;
+
+
+/**
+* @author: Chenzhenyong
+* @description: 字符串处理工具类
+* @date: Created in 10:27 2018/8/23
+*/
+public class StringUtil {
+
+	public static final String DEFAULT_CHARSET = "UTF-8";
+	
+	/**
+	 * 判断字符串是否为空
+	 * @param str
+	 * @return
+	 */
+	public static boolean isEmpty(String str){
+		int strLen;
+		if (str != null && (strLen = str.length()) != 0) {
+			for(int i = 0; i < strLen; ++i) {
+				if (!Character.isWhitespace(str.charAt(i))) {
+					return false;
+				}
+			}
+			return true;
+		} else {
+			return true;
+		}
+	}
+
+	/**
+	 *
+	 * @param data
+	 * @return
+	 */
+	public static byte[] getBytes(String data){
+		byte [] bytes = new byte[]{};
+		try {
+			bytes = data.getBytes(DEFAULT_CHARSET);
+		} catch (UnsupportedEncodingException e) {
+			e.printStackTrace();
+		}
+		return  bytes;
+	}
+
+	public static final String bytesToHexString(byte[] bArray) {
+		StringBuffer sb = new StringBuffer(bArray.length);
+
+		for(int i = 0; i < bArray.length; ++i) {
+			String sTemp = Integer.toHexString(255 & bArray[i]);
+			if (sTemp.length() < 2) {
+				sb.append(0);
+			}
+
+			sb.append(sTemp.toUpperCase());
+		}
+
+		return sb.toString();
+	}
+
+
+
+}

+ 120 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-api/src/main/java/com/sptg/permissions/api/thirdauth/util/XXTeaUtil.java

@@ -0,0 +1,120 @@
+package com.sptg.permissions.api.thirdauth.util;
+
+/**
+* @author: Chenzhenyong
+* @description: xxtea加解密工具类
+* @date: Created in 12:07 2018/7/24
+*/
+public class XXTeaUtil {
+    public XXTeaUtil() {
+    }
+
+    public static byte[] encrypt(byte[] plainData, byte[] key) {
+        return plainData != null && plainData.length != 0 && key != null ? toByteArray(encrypt(toIntArray(plainData, true), toIntArray(key, false)), false) : null;
+    }
+
+    public static byte[] decrypt(byte[] cipherData, byte[] key) {
+        return cipherData != null && cipherData.length != 0 && key != null ? toByteArray(decrypt(toIntArray(cipherData, false), toIntArray(key, false)), true) : null;
+    }
+
+    private static int[] encrypt(int[] v, int[] k) {
+        int n = v.length - 1;
+        if (n < 1) {
+            return v;
+        } else {
+            if (k.length < 4) {
+                int[] key = new int[4];
+                System.arraycopy(k, 0, key, 0, k.length);
+                k = key;
+            }
+
+            int z = v[n];
+            int y = v[0];
+            int delta = -1640531527;
+            int sum = 0;
+
+            int e;
+            int p;
+            for(int var9 = 6 + 52 / (n + 1); var9-- > 0; z = v[n] += (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z)) {
+                sum += delta;
+                e = sum >>> 2 & 3;
+
+                for(p = 0; p < n; ++p) {
+                    y = v[p + 1];
+                    z = v[p] += (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
+                }
+
+                y = v[0];
+            }
+
+            return v;
+        }
+    }
+
+    private static int[] decrypt(int[] v, int[] k) {
+        int n = v.length - 1;
+        if (n < 1) {
+            return v;
+        } else {
+            if (k.length < 4) {
+                int[] key = new int[4];
+                System.arraycopy(k, 0, key, 0, k.length);
+                k = key;
+            }
+
+            int var10000 = v[n];
+            int y = v[0];
+            int delta = -1640531527;
+            int q = 6 + 52 / (n + 1);
+
+            for(int sum = q * delta; sum != 0; sum -= delta) {
+                int e = sum >>> 2 & 3;
+
+                int p;
+                int z;
+                for(p = n; p > 0; --p) {
+                    z = v[p - 1];
+                    y = v[p] -= (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
+                }
+
+                z = v[n];
+                y = v[0] -= (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
+            }
+            return v;
+        }
+    }
+
+    private static int[] toIntArray(byte[] data, boolean includeLength) {
+        int n = (data.length & 3) == 0 ? data.length >>> 2 : (data.length >>> 2) + 1;
+        int[] result;
+        if (includeLength) {
+            result = new int[n + 1];
+            result[n] = data.length;
+        } else {
+            result = new int[n];
+        }
+        n = data.length;
+        for(int i = 0; i < n; ++i) {
+            result[i >>> 2] |= (255 & data[i]) << ((i & 3) << 3);
+        }
+        return result;
+    }
+
+    private static byte[] toByteArray(int[] data, boolean includeLength) {
+        int n = data.length << 2;
+        if (includeLength) {
+            int m = data[data.length - 1];
+            if (m > n || m <= 0) {
+                return null;
+            }
+
+            n = m;
+        }
+        byte[] result = new byte[n];
+        for(int i = 0; i < n; ++i) {
+            result[i] = (byte)(data[i >>> 2] >>> ((i & 3) << 3) & 255);
+        }
+        return result;
+    }
+
+}

+ 16 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-biz/src/main/java/com/sptg/permissions/biz/controller/AccountAuthenticationController.java

@@ -75,6 +75,22 @@ public class AccountAuthenticationController implements AccountAuthenticationFei
         return new ResultBean<>(PermissionsEnum.AUTHENTICATION_ERROR);
     }
 
+    @Override
+    @PostMapping(value = "/account/oauth/login")
+    public ResultBean<Account> oauthLogin(@RequestBody LoginDto loginDto) {
+        Account account = this.accountServiceInterface.selectByLoginName(loginDto.getLoginName());
+        if (null != account){
+            //  校验账号是否可用
+            if (OperationConstant.TWO == account.getIsEnable()){
+                return new ResultBean<>(PermissionsEnum.USER_NOT_ENABLE);
+            }
+            this.setupAccountAuthority(account);
+            return new ResultBean<>(ResultEnum.SUCCESS,account);
+        }
+        //  用户名或密码错误
+        return new ResultBean<>(PermissionsEnum.AUTHENTICATION_OAUTH_ERROR);
+    }
+
     @Override
     @GetMapping(value = "/account/reload/{id}")
     public Account reload(@PathVariable(value = "id")Serializable id) {

+ 7 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-biz/src/main/java/com/sptg/permissions/biz/controller/AccountController.java

@@ -333,6 +333,13 @@ public class AccountController implements AccountFeign {
         return this.accountServiceInterface.modifyPassword(account);
     }
 
+    @Override
+    @GetMapping(value = "/account/getByUserMobile")
+    public Account getByUserMobile(@RequestParam(value = "userMobile") String userMobile) {
+        Account account = this.accountServiceInterface.getByUserMobile(userMobile);
+        return account;
+    }
+
     public Boolean addEntityByAgency(Account account) {
         account.setLoginPwd(DigestUtils.sha256Hex(account.getLoginPwd()));
         boolean insert = this.accountServiceInterface.insert(account);

+ 72 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-biz/src/main/java/com/sptg/permissions/biz/controller/AccountOauthController.java

@@ -0,0 +1,72 @@
+package com.sptg.permissions.biz.controller;
+
+import com.baomidou.mybatisplus.plugins.Page;
+import com.sptg.common.core.beans.PageBean;
+import com.sptg.common.core.beans.ResultBean;
+import com.sptg.common.core.beans.ResultEnum;
+import com.sptg.common.core.constant.CommonConstant;
+import com.sptg.common.core.util.CommonUtil;
+import com.sptg.permissions.api.dto.AccountDto;
+import com.sptg.permissions.api.dto.AccountOauthDto;
+import com.sptg.permissions.api.entity.Account;
+import com.sptg.permissions.api.entity.AccountOauth;
+import com.sptg.permissions.api.entity.Role;
+import com.sptg.permissions.api.feigns.AccountOauthFeign;
+import com.sptg.permissions.api.feigns.AccountOauthFeign;
+import com.sptg.permissions.biz.service.AccountOauthServiceInterface;
+import com.sptg.permissions.biz.service.AccountServiceInterface;
+import com.sptg.permissions.biz.service.RoleServiceInterface;
+import lombok.RequiredArgsConstructor;
+import org.springframework.util.Assert;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * title: AccountOauthController
+ * package: com.sptg.permissions.biz.controller
+ * description: 账号授权-控制器
+ *
+ *
+ *
+ */
+@RestController
+@RequiredArgsConstructor
+public class AccountOauthController implements AccountOauthFeign {
+
+    private final AccountOauthServiceInterface accountOauthServiceInterface;
+    private final AccountServiceInterface accountServiceInterface;
+
+    @Override
+    @PostMapping(value = "/account/oauth/pagingQuery")
+    public ResultBean<Page> pagingQuery(@RequestBody PageBean<AccountOauth,AccountOauthDto> pageBean) {
+        Page<AccountOauth> page = this.accountOauthServiceInterface.pagingQuery(pageBean);
+        return new ResultBean<>(ResultEnum.SUCCESS,page);
+    }
+
+    @Override
+    @PostMapping(value = "/account/oauth/getByUuIdAndSource")
+    public ResultBean<AccountOauth> getByUuIdAndSource(@RequestBody AccountOauthDto dto) {
+        AccountOauth oauth = this.accountOauthServiceInterface.selectByUuIdAndSource(dto.getUuId(), dto.getSource());
+        return new ResultBean<>(ResultEnum.SUCCESS,oauth);
+    }
+
+    @Override
+    @PostMapping(value = "/account/oauth/bind")
+    public ResultBean<Boolean> bindUser(@RequestBody AccountOauthDto dto) {
+        //  获取账号信息
+        Boolean result = this.accountOauthServiceInterface.bindUser(dto);
+        return new ResultBean<>(ResultEnum.SUCCESS,result);
+    }
+
+    @Override
+    @PostMapping(value = "/account/oauth/untie")
+    public ResultBean<Boolean> untieUser(@RequestBody AccountOauthDto dto) {
+        Boolean result = this.accountOauthServiceInterface.untieUser(dto);
+        return new ResultBean<>(ResultEnum.SUCCESS,result);
+    }
+
+}

+ 22 - 23
smart-house-yinchuan/sptg-permissions/sptg-permissions-biz/src/main/java/com/sptg/permissions/biz/controller/CustInfoVerifyController.java

@@ -1,19 +1,15 @@
 package com.sptg.permissions.biz.controller;
 
+import cn.hutool.http.HttpUtil;
+import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
 import com.sptg.permissions.api.conf.CustInfoVerifyConfig;
-import com.sptg.permissions.api.entity.ApiLog;
 import com.sptg.permissions.api.entity.CustInfoResponse;
 import com.sptg.permissions.api.entity.CustInfoVerify;
 import com.sptg.permissions.api.feigns.CustInfoVerifyFeign;
-import com.sptg.permissions.biz.service.SysApiLogServiceInterface;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.core.ParameterizedTypeReference;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.ResponseEntity;
 import org.springframework.util.Assert;
 import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -44,37 +40,40 @@ public class CustInfoVerifyController implements CustInfoVerifyFeign {
         custInfoVerify.setCertNumber(certNumber.trim());
         custInfoVerify.setCustName(custName.trim());
         RestTemplate restTemplate = new RestTemplate();
-        HttpHeaders headers = new HttpHeaders();
+//        HttpHeaders headers = new HttpHeaders();
         String uuid = UUID.randomUUID().toString();
+        Map<String, String> headers = new HashMap<>();
         CustInfoVerifyConfig config = new CustInfoVerifyConfig();
-        headers.add("X-APP-ID", config.getAppId());
-        headers.add("X-APP-KEY", config.getAppKey());
-        headers.add("X-CTG-Request-ID",uuid);
-        headers.add("Content-Type", "text/xml;charset=utf-8");
+        headers.put("X-APP-ID", config.getAppId());
+        headers.put("X-APP-KEY", config.getAppKey());
+        headers.put("X-CTG-Request-ID",uuid);
+        headers.put("Content-Type", "text/xml;charset=utf-8");
         Map<String, Object> logMap = new HashMap<>();
         logMap.put("header", headers);
         logMap.put("body", custInfoVerify);
-        HttpEntity<String> requestEntity = new HttpEntity<>(JSONUtil.toJsonStr(custInfoVerify), headers);
+//        HttpEntity<String> requestEntity = new HttpEntity<>(JSONUtil.toJsonStr(custInfoVerify), headers);
         ParameterizedTypeReference<CustInfoResponse> reference = new ParameterizedTypeReference<CustInfoResponse>() {};
         String url = config.getHost();
         URI uri = URI.create(url);
         logMap.put("url", uri);
-        ResponseEntity<CustInfoResponse> result = null;
         try {
             log.warn("=====================身份证验证请求数据=========================");
-            log.warn(JSONUtil.toJsonStr(custInfoVerify));
-            result = restTemplate.exchange(uri, HttpMethod.POST, requestEntity, reference);
+            String bodyString = JSONUtil.toJsonStr(custInfoVerify);
+            log.warn(bodyString);
+            String result = HttpUtil.createPost(uri.toString()).addHeaders(headers).body(bodyString).execute().body();
             log.warn("=====================身份证验证响应数据=========================");
-            log.warn(JSONUtil.toJsonStr(result.getBody()));
-            logMap.put("result", result.getBody());
+            log.warn(result);
+            JSONObject data = JSONUtil.parseObj(result);
+            if("0".equals(data.getStr("code"))){
+                return true;
+            }else{
+                return false;
+            }
         }catch (Exception e){
-            logMap.put("result", e.getMessage());
-        }
-        CustInfoResponse response = result.getBody();
-        if(!"0".equals(response.getCode())){
+            e.printStackTrace();
+            log.warn("=====================身份证验证失败=========================");
+            log.warn(e.getMessage());
             return false;
-        }else{
-            return true;
         }
     }
 }

+ 66 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-biz/src/main/java/com/sptg/permissions/biz/controller/ThirdAuthenticationController.java

@@ -0,0 +1,66 @@
+package com.sptg.permissions.biz.controller;
+
+import com.sptg.common.core.beans.ResultBean;
+import com.sptg.common.core.beans.ResultEnum;
+import com.sptg.common.core.constant.OperationConstant;
+import com.sptg.common.core.util.TreeUtil;
+import com.sptg.permissions.api.dto.AccountDto;
+import com.sptg.permissions.api.dto.LoginDto;
+import com.sptg.permissions.api.entity.Account;
+import com.sptg.permissions.api.entity.Menu;
+import com.sptg.permissions.api.entity.Role;
+import com.sptg.permissions.api.enums.PermissionsEnum;
+import com.sptg.permissions.api.feigns.ThirdAuthenticationFeign;
+import com.sptg.permissions.api.thirdauth.util.AuthRequestUtil;
+import com.sptg.permissions.biz.service.AccountRoleServiceInterface;
+import com.sptg.permissions.biz.service.AccountServiceInterface;
+import com.sptg.permissions.biz.service.MenuServiceInterface;
+import com.sptg.permissions.biz.service.RoleServiceInterface;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import me.zhyd.oauth.model.AuthCallback;
+import me.zhyd.oauth.request.AuthRequest;
+import me.zhyd.oauth.utils.AuthStateUtils;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * title: ThirdAuthenticationController
+ * package: com.sptg.permissions.biz.controller
+ * description: 第三方授权认证-控制器
+ *
+ *                  
+ *                 
+ */
+@Slf4j
+@RestController
+@RequiredArgsConstructor
+public class ThirdAuthenticationController implements ThirdAuthenticationFeign {
+
+
+    @Override
+    @RequestMapping("/render/{source}")
+    @ResponseBody
+    public void renderAuth(String source, HttpServletResponse response) throws IOException {
+        log.info("进入render:" + source);
+        AuthRequest authRequest = AuthRequestUtil.getAuthRequest(source);
+        String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
+        log.info(authorizeUrl);
+        response.sendRedirect(authorizeUrl);
+    }
+
+    @Override
+    @RequestMapping("/callback/{source}")
+    public ModelAndView login(String source, AuthCallback callback, HttpServletRequest request) {
+        return null;
+    }
+
+}

+ 17 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-biz/src/main/java/com/sptg/permissions/biz/mapper/AccountOauthMapper.java

@@ -0,0 +1,17 @@
+package com.sptg.permissions.biz.mapper;
+
+import com.baomidou.mybatisplus.mapper.BaseMapper;
+import com.sptg.permissions.api.entity.AccountOauth;
+import com.sptg.permissions.api.entity.AccountOauth;
+
+/**
+ * title: AccountOauthMapper
+ * package: com.sptg.permissions.biz.mapper
+ * description: 账号角色关联表-DAO接口
+ *
+ *                  
+ *                 
+ */
+public interface AccountOauthMapper extends BaseMapper<AccountOauth> {
+
+}

+ 61 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-biz/src/main/java/com/sptg/permissions/biz/service/AccountOauthServiceInterface.java

@@ -0,0 +1,61 @@
+package com.sptg.permissions.biz.service;
+
+import com.baomidou.mybatisplus.plugins.Page;
+import com.sptg.common.core.beans.PageBean;
+import com.sptg.permissions.api.dto.AccountDto;
+import com.sptg.permissions.api.dto.AccountOauthDto;
+import com.sptg.permissions.api.entity.Account;
+import com.sptg.permissions.api.entity.AccountOauth;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * title: AccountOauthServiceInterface
+ * package: com.sptg.permissions.biz.security
+ * description: 账号角色-服务层接口
+ *
+ *                  
+ *                 
+ */
+public interface AccountOauthServiceInterface {
+
+
+    /**
+     * 功能描述: 根据第三方UUId和来源获取授权用户记录
+     * @param uuId 第三方UUID
+     * @return Long 用户Id
+     *
+     * date:  2018/10/29 22:12
+     */
+    AccountOauth selectByUuIdAndSource(String uuId, String source);
+
+
+    /**
+     * 功能描述: 根据第三方用户来源,分页后去的第三方授权账号列表
+     * @param pageBean 分页信息
+     * @return Page<AccountOauth>
+     *                  
+     *                       
+     */
+    Page<AccountOauth> pagingQuery(PageBean<AccountOauth,AccountOauthDto> pageBean);
+
+    /**
+     * 功能描述: 绑定用户
+     * @return Boolean { true:成功,false:失败 }
+     *                  
+     *                       
+     */
+    Boolean bindUser(AccountOauthDto dto);
+
+    /**
+     * 功能描述: 解除用户绑定
+     * @return ResultBean<Boolean>
+     *                  
+     *                       
+     */
+    Boolean untieUser(AccountOauthDto dto);
+
+
+
+}

+ 2 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-biz/src/main/java/com/sptg/permissions/biz/service/AccountServiceInterface.java

@@ -196,4 +196,6 @@ public interface AccountServiceInterface extends IService<Account> {
     ResultBean<String> resetPassword(Account dto);
 
     ResultBean<Boolean> modifyPassword(Account account);
+
+    Account getByUserMobile(String mobile);
 }

+ 114 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-biz/src/main/java/com/sptg/permissions/biz/service/impl/AccountOauthServiceImpl.java

@@ -0,0 +1,114 @@
+package com.sptg.permissions.biz.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.baomidou.mybatisplus.mapper.Wrapper;
+import com.baomidou.mybatisplus.plugins.Page;
+import com.baomidou.mybatisplus.service.impl.ServiceImpl;
+import com.sptg.common.core.beans.PageBean;
+import com.sptg.common.core.constant.OperationConstant;
+import com.sptg.common.core.util.CommonUtil;
+import com.sptg.permissions.api.dto.AccountDto;
+import com.sptg.permissions.api.dto.AccountOauthDto;
+import com.sptg.permissions.api.entity.Account;
+import com.sptg.permissions.api.entity.AccountOauth;
+import com.sptg.permissions.biz.mapper.AccountOauthMapper;
+import com.sptg.permissions.biz.service.AccountOauthServiceInterface;
+import com.sptg.permissions.biz.service.AccountServiceInterface;
+import com.sptg.permissions.biz.service.OrgServiceInterface;
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.StringUtils;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * title: AccountOauthServiceImpl
+ * package: com.sptg.permissions.biz.security.impl
+ * description: 账号第三方授权-服务层接口实现类
+ *
+ *                  
+ *                 
+ */
+@Service
+@RequiredArgsConstructor
+public class AccountOauthServiceImpl extends ServiceImpl<AccountOauthMapper, AccountOauth> implements AccountOauthServiceInterface {
+
+    private final AccountServiceInterface accountServiceInterface;
+
+    @Override
+    public AccountOauth selectByUuIdAndSource(String uuId, String source) {
+        Wrapper<AccountOauth> wrapper = new EntityWrapper<>();
+        wrapper.eq("s_source", source);
+        wrapper.eq("s_uuId", uuId);
+        AccountOauth oauth = this.selectOne(wrapper);
+        return oauth;
+    }
+
+    @Override
+    public Page<AccountOauth> pagingQuery(PageBean<AccountOauth,AccountOauthDto> pageBean) {
+        AccountOauthDto dto = pageBean.getDto();
+        //  获取用户的关联列表
+        Wrapper<AccountOauth> wrapper = new EntityWrapper<>();
+        wrapper.eq("s_source", dto.getSource());
+        wrapper.eq(StringUtils.hasText(dto.getUserName()), "s_user_name", dto.getUserName());
+        //  分页查询关联信息
+        return this.selectPage(pageBean, wrapper);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Throwable.class)
+    public Boolean bindUser(AccountOauthDto dto) {
+        Wrapper<AccountOauth> wrapper = new EntityWrapper<>();
+        wrapper.eq("s_source", dto.getSource());
+        wrapper.eq("s_uuId", dto.getUuId());
+        AccountOauth oauth = this.selectOne(wrapper);
+        if(oauth == null){
+            AccountOauth accountOauth = createAccountOauth(dto);
+            return (this.insert(accountOauth));
+        }else{
+            AccountOauth updateOauth = updateAccountOauth(oauth, dto);
+            boolean update = this.updateById(updateOauth);
+            return update;
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Throwable.class)
+    public Boolean untieUser(AccountOauthDto dto) {
+        Wrapper<AccountOauth> wrapper = new EntityWrapper<>();
+        wrapper.eq("s_source", dto.getSource());
+        wrapper.eq("s_uuId", dto.getUuId());
+        AccountOauth oauth = this.selectOne(wrapper);
+        oauth.setAccountId(null);
+        return this.updateById(oauth);
+    }
+
+    //新增授权用户
+    private AccountOauth createAccountOauth(AccountOauthDto dto){
+        AccountOauth oauth = BeanUtil.copyProperties(dto, AccountOauth.class);
+        Date date = new Date();
+        oauth.setCreateDate(date);
+        oauth.setUpdateDate(date);
+        return oauth;
+    }
+
+    //新增授权用户
+    private AccountOauth updateAccountOauth(AccountOauth old, AccountOauthDto _new){
+        old.setNickName(_new.getNickName());
+        old.setEmail(_new.getEmail());
+        old.setAvatar(_new.getAvatar());
+        if(_new.getAccountId() != null){
+            old.setAccountId(_new.getAccountId());
+        }
+        old.setUpdateDate(new Date());
+        return old;
+    }
+
+
+}

+ 9 - 0
smart-house-yinchuan/sptg-permissions/sptg-permissions-biz/src/main/java/com/sptg/permissions/biz/service/impl/AccountServiceImpl.java

@@ -452,5 +452,14 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
         return new ResultBean<>(ResultEnum.ERROR);
     }
 
+    @Override
+    public Account getByUserMobile(String mobile) {
+        Assert.hasText(mobile, "手机号必传");
+        Wrapper<Account> wrapper = new EntityWrapper<>();
+        wrapper.eq("s_user_mobile", mobile);
+        Account account = this.selectOne(wrapper);
+        return account;
+    }
+
 
 }

+ 28 - 0
szsq-boot-1/src/main/java/org/springblade/MyApplicationRunner.java

@@ -0,0 +1,28 @@
+package org.springblade;
+
+import org.springblade.mqtt.MqttRecieveCallback;
+import org.springblade.mqtt.MyMqttClient;
+import org.springblade.mqtt.TendaConfig;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+@Component
+@Order(value = 1)
+public class MyApplicationRunner implements ApplicationRunner {
+
+	@Autowired
+	private MyMqttClient myMqttClient;
+	@Autowired
+	private MqttRecieveCallback mqttReceriveCallback;
+	@Autowired
+	private TendaConfig tendaConfig;
+
+	@Override
+	public void run(ApplicationArguments args) throws Exception {
+		myMqttClient.init(tendaConfig, mqttReceriveCallback);
+		myMqttClient.subTopic(tendaConfig.getTopic());
+	}
+}

+ 56 - 0
szsq-boot-1/src/main/java/org/springblade/community/car/wrapper/CarWrapper.java

@@ -0,0 +1,56 @@
+/*
+ *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ *  Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *  Neither the name of the dreamlu.net developer nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *  Author: Chill 庄骞 (smallchill@163.com)
+ */
+package org.springblade.community.car.wrapper;
+
+
+import cn.hutool.core.util.DesensitizedUtil;
+import net.logstash.logback.encoder.org.apache.commons.lang3.StringUtils;
+import org.springblade.common.Constants;
+import org.springblade.community.applyuser.entity.ApplyUser;
+import org.springblade.community.applyuser.vo.ApplyUserVO;
+import org.springblade.community.car.entity.Car;
+import org.springblade.community.car.vo.CarVO;
+import org.springblade.core.mp.support.BaseEntityWrapper;
+import org.springblade.core.tool.utils.BeanUtil;
+import org.springblade.utils.AESPlus;
+
+import java.util.Objects;
+
+/**
+ * 包装类,返回视图层所需的字段
+ *
+ * @author BladeX
+ * @since 2020-11-06
+ */
+public class CarWrapper extends BaseEntityWrapper<Car, CarVO> {
+
+	private static final String SYMBOL = "*";
+
+	public static CarWrapper build() {
+		return new CarWrapper();
+ 	}
+
+	@Override
+	public CarVO entityVO(Car car) {
+		CarVO carVO = Objects.requireNonNull(BeanUtil.copy(car, CarVO.class));
+		carVO.setPersonName(DesensitizedUtil.chineseName(carVO.getPersonName()));
+		carVO.setNumber(DesensitizedUtil.carLicense(carVO.getNumber()));
+		carVO.setPersonPhone(DesensitizedUtil.mobilePhone(carVO.getPersonPhone()));
+		return carVO;
+	}
+
+}

+ 40 - 0
szsq-boot-1/src/main/java/org/springblade/config/SpringSecurityActuatorConfig.java

@@ -0,0 +1,40 @@
+package org.springblade.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+@Configuration
+@Slf4j
+public class SpringSecurityActuatorConfig extends WebSecurityConfigurerAdapter {
+
+	public SpringSecurityActuatorConfig() {
+		log.info("SpringSecurityActuatorConfig... start");
+	}
+
+	@Override
+	protected void configure(HttpSecurity http) throws Exception {
+//		//  这个配置只针对  /actuator/** 的请求生效
+		http.antMatcher("/actuator/**")
+			// /actuator/下所有请求都要认证
+			.authorizeRequests().anyRequest().authenticated()
+			// 启用httpBasic认证模式,当springboot admin-client 配置了密码时,
+			// admin-server走httpbasic的认证方式来拉取client的信息
+			.and().httpBasic()
+			// 禁用csrf
+			.and().csrf().disable();
+//		http.authorizeRequests()
+//			.antMatchers( "/actuator/**").permitAll()
+//			.antMatchers( "/instances").permitAll()
+//			.anyRequest().authenticated()
+//			.and()
+//			.formLogin()
+//			//.loginPage("/login")
+//			.permitAll()
+//			.and()
+//			.logout()
+//			.permitAll();
+
+	}
+}

+ 36 - 0
szsq-boot-1/src/main/java/org/springblade/config/Swagger2Config.java

@@ -0,0 +1,36 @@
+package org.springblade.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+//@Configuration
+//@EnableSwagger2
+public class Swagger2Config {
+
+	@Bean
+	public Docket createRestApi() {
+		return new Docket(DocumentationType.SWAGGER_2)
+			.apiInfo(apiInfo())
+			.select()
+			.apis(RequestHandlerSelectors.basePackage("org.springblade"))
+			.paths(PathSelectors.any())
+			.build();
+	}
+
+	private ApiInfo apiInfo() {
+		return new ApiInfoBuilder()
+			.title("数字社区接口API文档")
+			.description("宁夏数字社区平台")
+			.termsOfServiceUrl("https://szsq.nxzhsq.cn/community")
+			.contact("新邻科技")
+			.version("1.0")
+			.build();
+	}
+}

+ 25 - 0
szsq-boot-1/src/main/java/org/springblade/config/SwaggerWebMvcConfigure.java

@@ -0,0 +1,25 @@
+package org.springblade.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
+
+//@Configuration
+public class SwaggerWebMvcConfigure extends WebMvcConfigurationSupport {
+
+	/**
+		* 发现如果继承了WebMvcConfigurationSupport,则在yml中配置的相关内容会失效。 需要重新指定静态资源
+     *
+		 * @param registry
+     */
+	@Override
+	public void addResourceHandlers(ResourceHandlerRegistry registry) {
+		registry.addResourceHandler("/**").addResourceLocations(
+			"classpath:/static/");
+		registry.addResourceHandler("swagger-ui.html").addResourceLocations(
+			"classpath:/META-INF/resources/");
+		registry.addResourceHandler("/webjars/**").addResourceLocations(
+			"classpath:/META-INF/resources/webjars/");
+		super.addResourceHandlers(registry);
+	}
+}

+ 25 - 0
szsq-boot-1/src/main/java/org/springblade/test/TestClass.java

@@ -0,0 +1,25 @@
+package org.springblade.test;
+
+import io.github.swagger2markup.Swagger2MarkupConfig;
+import io.github.swagger2markup.Swagger2MarkupConverter;
+import io.github.swagger2markup.builder.Swagger2MarkupConfigBuilder;
+import io.github.swagger2markup.markup.builder.MarkupLanguage;
+
+import java.net.URL;
+import java.nio.file.Paths;
+
+public class TestClass {
+
+	public static void main(String[] args) throws Exception {
+		//    输出Ascii格式
+		Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()
+			.withMarkupLanguage(MarkupLanguage.ASCIIDOC)
+			.build();
+
+		Swagger2MarkupConverter.from(new URL("http://localhost:9527/v2/api-docs"))
+			.withConfig(config)
+			.build()
+//			.toFolder(Paths.get("src/docs/asciidoc/generated"));
+			.toFile(Paths.get("src/docs/asciidoc/generated/all"));
+	}
+}

+ 29 - 0
szsq-boot-2/src/main/java/org/springblade/config/SpringSecurityActuatorConfig.java

@@ -0,0 +1,29 @@
+package org.springblade.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+@Configuration
+@Slf4j
+public class SpringSecurityActuatorConfig extends WebSecurityConfigurerAdapter {
+
+	public SpringSecurityActuatorConfig() {
+		log.info("SpringSecurityActuatorConfig... start");
+	}
+
+	@Override
+	protected void configure(HttpSecurity http) throws Exception {
+		//  这个配置只针对  /actuator/** 的请求生效
+		http.antMatcher("/actuator/**")
+			// /actuator/下所有请求都要认证
+			.authorizeRequests().anyRequest().authenticated()
+			// 启用httpBasic认证模式,当springboot admin-client 配置了密码时,
+			// admin-server走httpbasic的认证方式来拉取client的信息
+			.and().httpBasic()
+			// 禁用csrf
+			.and().csrf().disable();
+
+	}
+}