Pārlūkot izejas kodu

Merge remote-tracking branch 'origin/master'

fangq 3 gadi atpakaļ
vecāks
revīzija
a2b95023ac
26 mainītis faili ar 1947 papildinājumiem un 21 dzēšanām
  1. 12 0
      smart-city-grid-yinchuan-manage/src/api/community/houseuser.js
  2. 5 0
      smart-city-grid-yinchuan-manage/src/api/user.js
  3. 8 8
      smart-city-grid-yinchuan-manage/src/page/login/index.vue
  4. 23 9
      smart-city-grid-yinchuan-manage/src/page/login/thirdlogin.vue
  5. 1 1
      smart-city-grid-yinchuan-manage/src/page/login/userlogin.vue
  6. 5 0
      smart-city-grid-yinchuan-manage/src/views/community/accessrecord.vue
  7. 7 1
      smart-city-grid-yinchuan-manage/src/views/community/permanentPeople.vue
  8. 2 2
      smart-city-grid-yinchuan-manage/src/views/community/personadd.vue
  9. 7 0
      smart-city-grid-yinchuan-server/pom.xml
  10. 2 0
      smart-city-grid-yinchuan-server/src/main/java/org/springblade/community/accessrecord/entity/AccessRecord.java
  11. 11 0
      smart-city-grid-yinchuan-server/src/main/java/org/springblade/community/houseuser/controller/HouseuserController.java
  12. 1 0
      smart-city-grid-yinchuan-server/src/main/java/org/springblade/openinterface/facedevice/jvt/controller/DeviceController.java
  13. 94 0
      smart-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/constants/CtwingAuthConstants.java
  14. 162 0
      smart-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/controller/CtwingController.java
  15. 30 0
      smart-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/enums/AuthCustomizeSource.java
  16. 109 0
      smart-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/officedemo/CtwingUnifyAccountLoginDemo.java
  17. 216 0
      smart-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/request/AuthCtwingRequest.java
  18. 34 0
      smart-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/util/AuthRequestUtil.java
  19. 51 0
      smart-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/util/ByteFormat.java
  20. 57 0
      smart-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/util/CtwingBase64Utils.java
  21. 308 0
      smart-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/util/CtwingRSAUtils.java
  22. 90 0
      smart-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/util/CtwingRequestUtil.java
  23. 306 0
      smart-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/util/HmacSha1Util.java
  24. 220 0
      smart-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/util/RSAUtil.java
  25. 66 0
      smart-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/util/StringUtil.java
  26. 120 0
      smart-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/util/XXTeaUtil.java

+ 12 - 0
smart-city-grid-yinchuan-manage/src/api/community/houseuser.js

@@ -71,6 +71,7 @@ export const elderlyList = (current, size, params) => {
   })
 }
 
+//脱敏数据
 export const getDetail = (id) => {
   return request({
     url: '/api/community/houseuser/detail',
@@ -81,6 +82,17 @@ export const getDetail = (id) => {
   })
 }
 
+//未脱敏数据
+export const getOne = (id) => {
+  return request({
+    url: '/api/community/houseuser/getOne',
+    method: 'get',
+    params: {
+      id
+    }
+  })
+}
+
 export const remove = (ids) => {
   return request({
     url: '/api/community/houseuser/remove',

+ 5 - 0
smart-city-grid-yinchuan-manage/src/api/user.js

@@ -63,3 +63,8 @@ export const clearCache = () => request({
   url: '/api/blade-auth/oauth/clear-cache',
   method: 'get'
 });
+
+export const thirdLogin = () => request({
+  url: '/api/ctwing/login/getCode',
+  method: 'get'
+});

+ 8 - 8
smart-city-grid-yinchuan-manage/src/page/login/index.vue

@@ -23,14 +23,14 @@
           <userLogin v-if="activeName==='user'"/>
           <codeLogin v-else-if="activeName==='code'"/>
           <thirdLogin v-else-if="activeName==='third'"/>
-<!--          <div class="login-menu">-->
-<!--            <a href="#"-->
-<!--               @click.stop="activeName='user'">{{ $t('login.userLogin') }}</a>-->
-<!--            <a href="#"-->
-<!--               @click.stop="activeName='code'">{{ $t('login.phoneLogin') }}</a>-->
-<!--            <a href="#"-->
-<!--               @click.stop="activeName='third'">{{ $t('login.thirdLogin') }}</a>-->
-<!--          </div>-->
+          <div class="login-menu">
+            <a href="#"
+               @click.stop="activeName='user'">{{ $t('login.userLogin') }}</a>
+            <!--<a href="#"
+               @click.stop="activeName='code'">{{ $t('login.phoneLogin') }}</a>-->
+            <a href="#"
+               @click.stop="activeName='third'">{{ $t('login.thirdLogin') }}</a>
+          </div>
         </div>
 
       </div>

+ 23 - 9
smart-city-grid-yinchuan-manage/src/page/login/thirdlogin.vue

@@ -1,15 +1,15 @@
 <template>
   <div class="social-container">
     <div class="box"
-         @click="handleClick('wechat')">
+         @click="handleClick('ctwing')">
       <span class="container"
             :style="{backgroundColor:'#6ba2d6'}">
-        <i icon-class="wechat"
-           class="iconfont icon-weixin"/>
+        <i icon-class="ctwing"
+           class="iconfont icon-ctwing"/>
       </span>
-      <p class="title">{{$t('login.wechat')}}</p>
+      <p class="title">天翼</p>
     </div>
-    <div class="box"
+    <!--<div class="box"
          @click="handleClick('tencent')">
       <span class="container"
             :style="{backgroundColor:'#8dc349'}">
@@ -17,18 +17,27 @@
            class="iconfont icon-qq"/>
       </span>
       <p class="title">{{$t('login.qq')}}</p>
-    </div>
+    </div>-->
   </div>
 </template>
 
 <script>
 import { openWindow } from "@/util/util";
+import {getCaptcha,thirdLogin} from "@/api/user";
 
 export default {
   name: "thirdLogin",
+  data() {
+    return {
+      thirdUrl: ''
+    }
+  },
   methods: {
+    tianyiLogin(){
+
+    },
     handleClick(thirdpart) {
-      let appid, client_id, redirect_uri, url;
+      /*let appid, client_id, redirect_uri, url;
       redirect_uri = encodeURIComponent(
         window.location.origin + "/#/authredirect"
       );
@@ -47,8 +56,13 @@ export default {
           client_id +
           "&redirect_uri=" +
           redirect_uri;
-      }
-      openWindow(url, thirdpart, 540, 540);
+      }*/
+      thirdLogin().then((res) => {
+        var data = res.data;
+        var url = data.data;
+        openWindow(url, thirdpart, 540, 540);
+      })
+
     }
   }
 };

+ 1 - 1
smart-city-grid-yinchuan-manage/src/page/login/userlogin.vue

@@ -66,7 +66,7 @@
 <script>
   import {mapGetters} from "vuex";
   import {info} from "@/api/system/tenant";
-  import {getCaptcha} from "@/api/user";
+  import {getCaptcha,thirdLogin} from "@/api/user";
   import {getByTenantId} from "@/api/system/options";
   import {getTenantTypeDetailByTenantId,getTenantInfo} from "@/api/system/tenant"
   export default {

+ 5 - 0
smart-city-grid-yinchuan-manage/src/views/community/accessrecord.vue

@@ -87,6 +87,11 @@
               prop: "faceUrl",
               slot: true,
             },
+            {
+              label: "人脸底图",
+              prop: "baseUrl",
+              slot: true,
+            },
             {
               label: "社区",
               prop: "agencyName",

+ 7 - 1
smart-city-grid-yinchuan-manage/src/views/community/permanentPeople.vue

@@ -72,6 +72,7 @@
 import {
   getList,
   getDetail,
+  getOne,
   add,
   update,
   convertToHouseUser,
@@ -945,7 +946,12 @@ import CyExcelImport from "../../components/excel/cy-excel-import";
           });
       },
       beforeOpen(done, type) {
-        if (["edit", "view"].includes(type)) {
+        if (["edit"].includes(type)) {
+          getOne(this.form.id).then(res => {
+            this.form = res.data.data;
+          });
+        }
+        if (["view"].includes(type)) {
           getDetail(this.form.id).then(res => {
             this.form = res.data.data;
           });

+ 2 - 2
smart-city-grid-yinchuan-manage/src/views/community/personadd.vue

@@ -90,7 +90,7 @@
 </template>
 
 <script>
-import { add,update,getDetail, getMoreDetail } from "@/api/community/houseuser";
+import { add,update,getOne, getMoreDetail } from "@/api/community/houseuser";
 
 export default {
   name: "personadd",
@@ -409,7 +409,7 @@ export default {
   },
   created() {
     if (this.personId){
-      getDetail(this.personId).then(res =>{
+      getOne(this.personId).then(res =>{
         this.person = res.data.data;
         if (this.person.personTag){
           this.tag = this.person.personTag.split(",");

+ 7 - 0
smart-city-grid-yinchuan-server/pom.xml

@@ -17,6 +17,7 @@
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
         <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
+        <just.auth>1.16.5</just.auth>
     </properties>
     <dependencyManagement>
         <dependencies>
@@ -158,6 +159,12 @@
             <version>1.2.1</version>
         </dependency>
 
+        <dependency>
+            <groupId>me.zhyd.oauth</groupId>
+            <artifactId>JustAuth</artifactId>
+            <version>${just.auth}</version>
+        </dependency>
+
 
     </dependencies>
     <build>

+ 2 - 0
smart-city-grid-yinchuan-server/src/main/java/org/springblade/community/accessrecord/entity/AccessRecord.java

@@ -91,6 +91,8 @@ public class AccessRecord extends BaseEntity {
 		@ApiModelProperty(value = "人脸")
 		private String faceUrl;
 
+		@ApiModelProperty(value = "底图")
+		private String baseUrl;
 	/**
 	 * 设备id
 	 */

+ 11 - 0
smart-city-grid-yinchuan-server/src/main/java/org/springblade/community/houseuser/controller/HouseuserController.java

@@ -117,6 +117,17 @@ public class HouseuserController extends BladeController {
 	@ApiOperationSupport(order = 1)
 	@ApiOperation(value = "详情", notes = "传入houseuser")
 	public R<Houseuser> detail(Houseuser houseuser) {
+		Houseuser detail = houseuserService.getOne(Condition.getQueryWrapper(houseuser));
+		return R.data(HouseuserWrapper.build().entityVO(detail));
+	}
+
+	/**
+	 * 详情未脱敏
+	 */
+	@GetMapping("/getOne")
+	@ApiOperationSupport(order = 1)
+	@ApiOperation(value = "详情", notes = "传入houseuser")
+	public R<Houseuser> getOne(Houseuser houseuser) {
 		Houseuser detail = houseuserService.getOne(Condition.getQueryWrapper(houseuser));
 		return R.data(detail);
 	}

+ 1 - 0
smart-city-grid-yinchuan-server/src/main/java/org/springblade/openinterface/facedevice/jvt/controller/DeviceController.java

@@ -228,6 +228,7 @@ public class DeviceController {
 			accessRecord.setFaceUrl(faceUrl);
 			accessRecord.setOrgPosition(residential.getOrgPosition());
 			accessRecord.setTenantId(residential.getTenantId());
+			accessRecord.setBaseUrl(houseuser.getImageUri());
 			this.accessRecordService.save(accessRecord);
 		}
 	}

+ 94 - 0
smart-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/constants/CtwingAuthConstants.java

@@ -0,0 +1,94 @@
+package org.springblade.third.auth.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://m8gp5z2irl.51xd.pub/ctwing/login/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";
+
+
+}

+ 162 - 0
smart-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/controller/CtwingController.java

@@ -0,0 +1,162 @@
+package org.springblade.third.auth.controller;
+
+import com.alibaba.fastjson.JSONObject;
+import com.xkcoding.http.util.MapUtil;
+import lombok.AllArgsConstructor;
+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 org.springblade.core.tool.api.R;
+import org.springblade.third.auth.constants.CtwingAuthConstants;
+import org.springblade.third.auth.request.AuthCtwingRequest;
+import org.springblade.third.auth.util.AuthRequestUtil;
+import org.springblade.third.auth.util.ByteFormat;
+import org.springblade.third.auth.util.HmacSha1Util;
+import org.springblade.third.auth.util.XXTeaUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @description:
+ * @author:xuanyan
+ * @create: 2022-09-29 09:57
+ **/
+@Slf4j
+@RestController
+@AllArgsConstructor
+@RequestMapping("ctwing/login")
+public class CtwingController {
+
+	@GetMapping("/getCode")
+	public R getCode(){
+		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按照本接口规范定义的参数处理方式接收和处理。
+
+			return R.data(webLoginBxUrl);
+		} catch (Exception e){
+			log.error("unifyAccountLogin demo error:",e);
+			return R.status(false);
+		}
+	}
+
+	/**
+	 * 生成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);
+	}
+
+	@RequestMapping("/callBack/{source}")
+	public void ctwingCallBack(@PathVariable("source") String source, AuthCallback callback, HttpServletRequest request){
+		AuthRequest authRequest = AuthRequestUtil.getAuthRequest(source);
+		callback = this.getAuthCallback(source, callback, request);
+		AuthResponse<AuthUser> response = authRequest.login(callback);
+		log.warn(JSONObject.toJSONString(response));
+
+		if (callback.getCode() != null) {
+
+		}
+	}
+
+	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;
+	}
+
+}

+ 30 - 0
smart-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/enums/AuthCustomizeSource.java

@@ -0,0 +1,30 @@
+package org.springblade.third.auth.enums;
+
+import me.zhyd.oauth.config.AuthSource;
+import me.zhyd.oauth.request.AuthDefaultRequest;
+import org.springblade.third.auth.constants.CtwingAuthConstants;
+import org.springblade.third.auth.request.AuthCtwingRequest;
+
+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-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/officedemo/CtwingUnifyAccountLoginDemo.java

@@ -0,0 +1,109 @@
+package org.springblade.third.auth.officedemo;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springblade.third.auth.constants.CtwingAuthConstants;
+import org.springblade.third.auth.util.ByteFormat;
+import org.springblade.third.auth.util.HmacSha1Util;
+import org.springblade.third.auth.util.XXTeaUtil;
+
+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-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/request/AuthCtwingRequest.java

@@ -0,0 +1,216 @@
+package org.springblade.third.auth.request;
+
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpUtil;
+import com.alibaba.fastjson.JSONObject;
+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 org.springblade.third.auth.constants.CtwingAuthConstants;
+import org.springblade.third.auth.enums.AuthCustomizeSource;
+import org.springblade.third.auth.util.*;
+
+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-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/util/AuthRequestUtil.java

@@ -0,0 +1,34 @@
+package org.springblade.third.auth.util;
+
+import me.zhyd.oauth.config.AuthConfig;
+import me.zhyd.oauth.exception.AuthException;
+import me.zhyd.oauth.request.*;
+import org.springblade.third.auth.request.AuthCtwingRequest;
+
+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://m8gp5z2irl.51xd.pub/ctwing/login/callback/ctwing")
+                        .build());
+                break;
+            default:
+                break;
+        }
+        if (null == authRequest) {
+            throw new AuthException("未获取到有效的Auth配置");
+        }
+        return authRequest;
+    }
+}

+ 51 - 0
smart-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/util/ByteFormat.java

@@ -0,0 +1,51 @@
+package org.springblade.third.auth.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;
+        }
+    }
+}

+ 57 - 0
smart-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/util/CtwingBase64Utils.java

@@ -0,0 +1,57 @@
+package org.springblade.third.auth.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);
+    }
+
+
+}

+ 308 - 0
smart-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/util/CtwingRSAUtils.java

@@ -0,0 +1,308 @@
+package org.springblade.third.auth.util;
+
+import sun.misc.BASE64Decoder;
+
+import javax.crypto.Cipher;
+import java.io.ByteArrayOutputStream;
+import java.security.*;
+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;
+
+/**
+* @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-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/util/CtwingRequestUtil.java

@@ -0,0 +1,90 @@
+package org.springblade.third.auth.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-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/util/HmacSha1Util.java

@@ -0,0 +1,306 @@
+package org.springblade.third.auth.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-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/util/RSAUtil.java

@@ -0,0 +1,220 @@
+package org.springblade.third.auth.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-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/util/StringUtil.java

@@ -0,0 +1,66 @@
+package org.springblade.third.auth.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-city-grid-yinchuan-server/src/main/java/org/springblade/third/auth/util/XXTeaUtil.java

@@ -0,0 +1,120 @@
+package org.springblade.third.auth.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;
+    }
+
+}