Browse Source

init from phab

xielq 4 years ago
parent
commit
a1c2f3f642
22 changed files with 1357 additions and 0 deletions
  1. 0 0
      README.md
  2. 39 0
      Readme.md
  3. 42 0
      build.gradle
  4. 2 0
      settings.gradle
  5. 17 0
      src/main/java/com/uas/account/sso/integration/config/EnableSSO.java
  6. 31 0
      src/main/java/com/uas/account/sso/integration/config/SSOConfiguration.java
  7. 14 0
      src/main/java/com/uas/account/sso/integration/config/SSOInitializer.java
  8. 75 0
      src/main/java/com/uas/account/sso/integration/crypto/SSOEncrypt.java
  9. 104 0
      src/main/java/com/uas/account/sso/integration/crypto/base64/UrlBase64.java
  10. 275 0
      src/main/java/com/uas/account/sso/integration/crypto/base64/UrlBase64Encoder.java
  11. 203 0
      src/main/java/com/uas/account/sso/integration/entity/UserView.java
  12. 20 0
      src/main/java/com/uas/account/sso/integration/exception/SSOException.java
  13. 27 0
      src/main/java/com/uas/account/sso/integration/function/Unchecked.java
  14. 27 0
      src/main/java/com/uas/account/sso/integration/util/CookieUtils.java
  15. 39 0
      src/main/java/com/uas/account/sso/integration/util/SSO.java
  16. 87 0
      src/main/java/com/uas/account/sso/integration/web/AbstractSSOInitializer.java
  17. 39 0
      src/main/java/com/uas/account/sso/integration/web/SSOFilter.java
  18. 47 0
      src/main/java/com/uas/account/sso/integration/web/SSOProperties.java
  19. 43 0
      src/main/java/com/uas/account/sso/integration/web/SSORepository.java
  20. 113 0
      src/main/java/com/uas/account/sso/integration/web/SSOToken.java
  21. 18 0
      src/test/java/com/uas/account/test/CryptoTest.java
  22. 95 0
      src/test/java/com/uas/account/test/MapperTest.java

+ 0 - 0
README.md


+ 39 - 0
Readme.md

@@ -0,0 +1,39 @@
+# 功能
+> 适用于spring boot项目,实现用户拦截与用户信息获取
+
+# 原理
+> 基于cookie身份标识uid识别用户认证信息
+
+# 使用方法
+> Gradle依赖
+```
+compile "com.uas.account:sso-integration:1.0-SNAPSHOT"
+```
+
+> 添加配置注入
+```
+@EnableSSO
+public class MyApplication {
+```
+
+> 添加sso配置
+
+```
+    sso:
+      secretKey: 0taQcW073Z7G628g5H
+```          
+
+> 使用
+```
+    @RequestMapping({"/", "/sso"})
+    public ResponseEntity test() {
+        // ssoToken
+        return ResponseEntity.ok(SSO.get());
+    }
+
+    @RequestMapping("/user")
+    public ResponseEntity test2() {
+        // ssoToken.data
+        return ResponseEntity.ok(UserView.get());
+    }
+```

+ 42 - 0
build.gradle

@@ -0,0 +1,42 @@
+group 'com.uas.account'
+version '1.0-SNAPSHOT'
+
+buildscript {
+    repositories {
+        maven { url "http://maven.aliyun.com/nexus/content/groups/public/" }
+        maven { url "https://plugins.gradle.org/m2/" }
+        maven { url "https://repo.spring.io/libs-release" }
+        mavenCentral()
+        jcenter()
+    }
+}
+
+apply plugin: 'java'
+apply plugin: 'maven'
+
+sourceCompatibility = 1.8
+
+repositories {
+    mavenLocal()
+    maven { url "http://repo.spring.io/libs-release" }
+    maven { url "http://maven.aliyun.com/nexus/content/groups/public/" }
+    mavenCentral()
+}
+
+dependencies {
+    compile "org.springframework.boot:spring-boot:1.5.9.RELEASE"
+    compile "org.springframework:spring-web:4.3.4.RELEASE"
+    compile "javax.validation:validation-api:1.1.0.Final"
+    compileOnly "javax.servlet:javax.servlet-api:3.0.1"
+    compile "com.fasterxml.jackson.core:jackson-databind:2.8.10"
+}
+
+uploadArchives {
+    repositories {
+        mavenDeployer {
+            repository(url: "http://10.10.101.21:8081/artifactory/libs-snapshot-local") {
+                authentication(userName: "yingp", password: "111111")
+            }
+        }
+    }
+}.dependsOn build

+ 2 - 0
settings.gradle

@@ -0,0 +1,2 @@
+rootProject.name = 'sso-integration'
+

+ 17 - 0
src/main/java/com/uas/account/sso/integration/config/EnableSSO.java

@@ -0,0 +1,17 @@
+package com.uas.account.sso.integration.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+
+import java.lang.annotation.*;
+
+/**
+ * Created by Pro1 on 2018/1/25.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+@Documented
+@Import({SSOConfiguration.class})
+@Configuration
+public @interface EnableSSO {
+}

+ 31 - 0
src/main/java/com/uas/account/sso/integration/config/SSOConfiguration.java

@@ -0,0 +1,31 @@
+package com.uas.account.sso.integration.config;
+
+import com.uas.account.sso.integration.web.SSOFilter;
+import com.uas.account.sso.integration.web.SSOProperties;
+import com.uas.account.sso.integration.web.SSORepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Created by Pro1 on 2018/1/25.
+ */
+@Configuration
+@EnableConfigurationProperties(SSOProperties.class)
+public class SSOConfiguration {
+
+    @Autowired
+    private SSOProperties ssoProperties;
+
+    @Bean
+    public SSORepository ssoRepository() {
+        return new SSORepository(ssoProperties);
+    }
+
+    @Bean
+    public SSOFilter ssoFilter() {
+        return new SSOFilter(ssoRepository());
+    }
+
+}

+ 14 - 0
src/main/java/com/uas/account/sso/integration/config/SSOInitializer.java

@@ -0,0 +1,14 @@
+package com.uas.account.sso.integration.config;
+
+import com.uas.account.sso.integration.web.AbstractSSOInitializer;
+
+/**
+ * Created by Pro1 on 2018/1/25.
+ */
+public class SSOInitializer extends AbstractSSOInitializer {
+
+    public SSOInitializer() {
+        super(SSOConfiguration.class);
+    }
+
+}

+ 75 - 0
src/main/java/com/uas/account/sso/integration/crypto/SSOEncrypt.java

@@ -0,0 +1,75 @@
+package com.uas.account.sso.integration.crypto;
+
+import com.uas.account.sso.integration.crypto.base64.UrlBase64;
+import com.uas.account.sso.integration.exception.SSOException;
+import org.springframework.util.DigestUtils;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * Created by Pro1 on 2018/1/25.
+ */
+public class SSOEncrypt {
+
+    final static String ALGORITHM = "RC4";
+
+    final static String defaultCharset = "UTF-8";
+
+    public static String encrypt(String value, String key) throws Exception {
+        byte[] b = UrlBase64.encode(encrypt(value.getBytes(), key));
+        return new String(b, defaultCharset);
+    }
+
+    public static String decrypt(String value, String key) throws Exception {
+        byte[] b = decrypt(UrlBase64.decode(value), key);
+        return new String(b, defaultCharset);
+    }
+
+    /**
+     * generate KEY
+     */
+    private static SecretKey toKey(String strKey) throws Exception {
+		/*
+		 * MD5 处理密钥
+		 */
+        byte[] key = DigestUtils.md5Digest(strKey.getBytes(defaultCharset));
+        return new SecretKeySpec(key, ALGORITHM);
+    }
+
+    /**
+     * 解密
+     *
+     * @param data
+     * @param key
+     * @return
+     */
+    public static byte[] decrypt(byte[] data, String key) {
+        try {
+            Cipher cipher = Cipher.getInstance(ALGORITHM);
+            cipher.init(Cipher.DECRYPT_MODE, toKey(key));
+            return cipher.doFinal(data);
+        } catch (Exception e) {
+            throw new SSOException(e);
+        }
+    }
+
+    /**
+     * 加密
+     *
+     * @param data
+     * @param key
+     * @return
+     */
+    public static byte[] encrypt(byte[] data, String key) {
+        try {
+            Cipher cipher = Cipher.getInstance(ALGORITHM);
+            cipher.init(Cipher.ENCRYPT_MODE, toKey(key));
+            return cipher.doFinal(data);
+        } catch (Exception e) {
+            throw new SSOException(e);
+        }
+    }
+
+}

+ 104 - 0
src/main/java/com/uas/account/sso/integration/crypto/base64/UrlBase64.java

@@ -0,0 +1,104 @@
+package com.uas.account.sso.integration.crypto.base64;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Convert binary data to and from UrlBase64 encoding. This is identical to
+ * Base64 encoding, except that the padding character is "." and the other
+ * non-alphanumeric characters are "-" and "_" instead of "+" and "/".
+ * <p>
+ * The purpose of UrlBase64 encoding is to provide a compact encoding of binary
+ * data that is safe for use as an URL parameter. Base64 encoding does not
+ * produce encoded values that are safe for use in URLs, since "/" can be
+ * interpreted as a path delimiter; "+" is the encoded form of a space; and "="
+ * is used to separate a name from the corresponding value in an URL parameter.
+ */
+public class UrlBase64 {
+
+	private static final UrlBase64Encoder encoder = new UrlBase64Encoder();
+
+	/**
+	 * Encode the input data producing a URL safe base 64 encoded byte array.
+	 *
+	 * @return a byte array containing the URL safe base 64 encoded data.
+	 */
+	public static byte[] encode(byte[] data) {
+		ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+		try {
+			encoder.encode(data, 0, data.length, bOut);
+		} catch (Exception e) {
+			throw new IllegalStateException("exception encoding URL safe base64 data: " + e.getMessage(), e);
+		}
+
+		return bOut.toByteArray();
+	}
+
+	/**
+	 * Encode the byte data writing it to the given output stream.
+	 *
+	 * @return the number of bytes produced.
+	 */
+	public static int encode(byte[] data, OutputStream out) throws IOException {
+		return encoder.encode(data, 0, data.length, out);
+	}
+
+	/**
+	 * Decode the URL safe base 64 encoded input data - white space will be
+	 * ignored.
+	 *
+	 * @return a byte array representing the decoded data.
+	 */
+	public static byte[] decode(byte[] data) {
+		ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+		try {
+			encoder.decode(data, 0, data.length, bOut);
+		} catch (Exception e) {
+			throw new IllegalStateException("exception decoding URL safe base64 string: " + e.getMessage(), e);
+		}
+
+		return bOut.toByteArray();
+	}
+
+	/**
+	 * decode the URL safe base 64 encoded byte data writing it to the given
+	 * output stream, whitespace characters will be ignored.
+	 *
+	 * @return the number of bytes produced.
+	 */
+	public static int decode(byte[] data, OutputStream out) throws IOException {
+		return encoder.decode(data, 0, data.length, out);
+	}
+
+	/**
+	 * decode the URL safe base 64 encoded String data - whitespace will be
+	 * ignored.
+	 *
+	 * @return a byte array representing the decoded data.
+	 */
+	public static byte[] decode(String data) {
+		ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+		try {
+			encoder.decode(data, bOut);
+		} catch (Exception e) {
+			throw new IllegalStateException("exception decoding URL safe base64 string: " + e.getMessage(), e);
+		}
+
+		return bOut.toByteArray();
+	}
+
+	/**
+	 * Decode the URL safe base 64 encoded String data writing it to the given
+	 * output stream, whitespace characters will be ignored.
+	 *
+	 * @return the number of bytes produced.
+	 */
+	public static int decode(String data, OutputStream out) throws IOException {
+		return encoder.decode(data, out);
+	}
+
+}

+ 275 - 0
src/main/java/com/uas/account/sso/integration/crypto/base64/UrlBase64Encoder.java

@@ -0,0 +1,275 @@
+package com.uas.account.sso.integration.crypto.base64;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Created by Pro1 on 2018/1/26.
+ */
+public class UrlBase64Encoder {
+    protected final byte[] encodingTable = { (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G',
+            (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', (byte) 'Q',
+            (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) 'a',
+            (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k',
+            (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u',
+            (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4',
+            (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) '-', (byte) '_' };
+
+    protected byte padding = (byte) '.';
+
+    /*
+     * set up the decoding table.
+     */
+    protected final byte[] decodingTable = new byte[128];
+
+    protected void initialiseDecodingTable() {
+        for (int i = 0; i < decodingTable.length; i++) {
+            decodingTable[i] = (byte) 0xff;
+        }
+
+        for (int i = 0; i < encodingTable.length; i++) {
+            decodingTable[encodingTable[i]] = (byte) i;
+        }
+    }
+
+    public UrlBase64Encoder() {
+        initialiseDecodingTable();
+    }
+
+    /**
+     * encode the input data producing a base 64 output stream.
+     *
+     * @return the number of bytes produced.
+     */
+    public int encode(byte[] data, int off, int length, OutputStream out) throws IOException {
+        int modulus = length % 3;
+        int dataLength = (length - modulus);
+        int a1, a2, a3;
+
+        for (int i = off; i < off + dataLength; i += 3) {
+            a1 = data[i] & 0xff;
+            a2 = data[i + 1] & 0xff;
+            a3 = data[i + 2] & 0xff;
+
+            out.write(encodingTable[(a1 >>> 2) & 0x3f]);
+            out.write(encodingTable[((a1 << 4) | (a2 >>> 4)) & 0x3f]);
+            out.write(encodingTable[((a2 << 2) | (a3 >>> 6)) & 0x3f]);
+            out.write(encodingTable[a3 & 0x3f]);
+        }
+
+		/*
+		 * process the tail end.
+		 */
+        int b1, b2, b3;
+        int d1, d2;
+
+        switch (modulus) {
+            case 0: /* nothing left to do */
+                break;
+            case 1:
+                d1 = data[off + dataLength] & 0xff;
+                b1 = (d1 >>> 2) & 0x3f;
+                b2 = (d1 << 4) & 0x3f;
+
+                out.write(encodingTable[b1]);
+                out.write(encodingTable[b2]);
+                out.write(padding);
+                out.write(padding);
+                break;
+            case 2:
+                d1 = data[off + dataLength] & 0xff;
+                d2 = data[off + dataLength + 1] & 0xff;
+
+                b1 = (d1 >>> 2) & 0x3f;
+                b2 = ((d1 << 4) | (d2 >>> 4)) & 0x3f;
+                b3 = (d2 << 2) & 0x3f;
+
+                out.write(encodingTable[b1]);
+                out.write(encodingTable[b2]);
+                out.write(encodingTable[b3]);
+                out.write(padding);
+                break;
+        }
+
+        return (dataLength / 3) * 4 + ((modulus == 0) ? 0 : 4);
+    }
+
+    private boolean ignore(char c) {
+        return (c == '\n' || c == '\r' || c == '\t' || c == ' ');
+    }
+
+    /**
+     * decode the base 64 encoded byte data writing it to the given output
+     * stream, whitespace characters will be ignored.
+     *
+     * @return the number of bytes produced.
+     */
+    public int decode(byte[] data, int off, int length, OutputStream out) throws IOException {
+        byte b1, b2, b3, b4;
+        int outLen = 0;
+
+        int end = off + length;
+
+        while (end > off) {
+            if (!ignore((char) data[end - 1])) {
+                break;
+            }
+
+            end--;
+        }
+
+        int i = off;
+        int finish = end - 4;
+
+        i = nextI(data, i, finish);
+
+        while (i < finish) {
+            b1 = decodingTable[data[i++]];
+
+            i = nextI(data, i, finish);
+
+            b2 = decodingTable[data[i++]];
+
+            i = nextI(data, i, finish);
+
+            b3 = decodingTable[data[i++]];
+
+            i = nextI(data, i, finish);
+
+            b4 = decodingTable[data[i++]];
+
+            if ((b1 | b2 | b3 | b4) < 0) {
+                throw new IOException("invalid characters encountered in base64 data");
+            }
+
+            out.write((b1 << 2) | (b2 >> 4));
+            out.write((b2 << 4) | (b3 >> 2));
+            out.write((b3 << 6) | b4);
+
+            outLen += 3;
+
+            i = nextI(data, i, finish);
+        }
+
+        outLen += decodeLastBlock(out, (char) data[end - 4], (char) data[end - 3], (char) data[end - 2], (char) data[end - 1]);
+
+        return outLen;
+    }
+
+    private int nextI(byte[] data, int i, int finish) {
+        while ((i < finish) && ignore((char) data[i])) {
+            i++;
+        }
+        return i;
+    }
+
+    /**
+     * decode the base 64 encoded String data writing it to the given output
+     * stream, whitespace characters will be ignored.
+     *
+     * @return the number of bytes produced.
+     */
+    public int decode(String data, OutputStream out) throws IOException {
+        byte b1, b2, b3, b4;
+        int length = 0;
+
+        int end = data.length();
+
+        while (end > 0) {
+            if (!ignore(data.charAt(end - 1))) {
+                break;
+            }
+
+            end--;
+        }
+
+        int i = 0;
+        int finish = end - 4;
+
+        i = nextI(data, i, finish);
+
+        while (i < finish) {
+            b1 = decodingTable[data.charAt(i++)];
+
+            i = nextI(data, i, finish);
+
+            b2 = decodingTable[data.charAt(i++)];
+
+            i = nextI(data, i, finish);
+
+            b3 = decodingTable[data.charAt(i++)];
+
+            i = nextI(data, i, finish);
+
+            b4 = decodingTable[data.charAt(i++)];
+
+            if ((b1 | b2 | b3 | b4) < 0) {
+                throw new IOException("invalid characters encountered in base64 data");
+            }
+
+            out.write((b1 << 2) | (b2 >> 4));
+            out.write((b2 << 4) | (b3 >> 2));
+            out.write((b3 << 6) | b4);
+
+            length += 3;
+
+            i = nextI(data, i, finish);
+        }
+
+        length += decodeLastBlock(out, data.charAt(end - 4), data.charAt(end - 3), data.charAt(end - 2), data.charAt(end - 1));
+
+        return length;
+    }
+
+    private int decodeLastBlock(OutputStream out, char c1, char c2, char c3, char c4) throws IOException {
+        byte b1, b2, b3, b4;
+
+        if (c3 == padding) {
+            b1 = decodingTable[c1];
+            b2 = decodingTable[c2];
+
+            if ((b1 | b2) < 0) {
+                throw new IOException("invalid characters encountered at end of base64 data");
+            }
+
+            out.write((b1 << 2) | (b2 >> 4));
+
+            return 1;
+        } else if (c4 == padding) {
+            b1 = decodingTable[c1];
+            b2 = decodingTable[c2];
+            b3 = decodingTable[c3];
+
+            if ((b1 | b2 | b3) < 0) {
+                throw new IOException("invalid characters encountered at end of base64 data");
+            }
+
+            out.write((b1 << 2) | (b2 >> 4));
+            out.write((b2 << 4) | (b3 >> 2));
+
+            return 2;
+        } else {
+            b1 = decodingTable[c1];
+            b2 = decodingTable[c2];
+            b3 = decodingTable[c3];
+            b4 = decodingTable[c4];
+
+            if ((b1 | b2 | b3 | b4) < 0) {
+                throw new IOException("invalid characters encountered at end of base64 data");
+            }
+
+            out.write((b1 << 2) | (b2 >> 4));
+            out.write((b2 << 4) | (b3 >> 2));
+            out.write((b3 << 6) | b4);
+
+            return 3;
+        }
+    }
+
+    private int nextI(String data, int i, int finish) {
+        while ((i < finish) && ignore(data.charAt(i))) {
+            i++;
+        }
+        return i;
+    }
+}

+ 203 - 0
src/main/java/com/uas/account/sso/integration/entity/UserView.java

@@ -0,0 +1,203 @@
+package com.uas.account.sso.integration.entity;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.uas.account.sso.integration.util.SSO;
+
+import java.io.Serializable;
+
+/**
+ * Created by Pro1 on 2018/1/25.
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class UserView implements Serializable {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    private String appId;
+
+    private Long spaceId;
+
+    private String spaceUID;
+
+    private String spaceDialectUID;
+
+    private Long id;
+
+    private String uid;
+
+    private String secondUID;
+
+    private String dialectUID;
+
+    private String name;
+
+    private String password;
+
+    private String salt;
+
+    private Short hr;
+
+    private Short pwdSecLevel;
+
+    private Long lastLoginTime;
+
+    private String uu;
+
+    /**
+     * 用户集名称
+     */
+    private String spaceName;
+
+    /**
+     * 企业域名
+     */
+    private String spaceDomain;
+
+    public String getAppId() {
+        return appId;
+    }
+
+    public void setAppId(String appId) {
+        this.appId = appId;
+    }
+
+    public Long getSpaceId() {
+        return spaceId;
+    }
+
+    public void setSpaceId(Long spaceId) {
+        this.spaceId = spaceId;
+    }
+
+    public String getSpaceUID() {
+        return spaceUID;
+    }
+
+    public void setSpaceUID(String spaceUID) {
+        this.spaceUID = spaceUID;
+    }
+
+    public String getSpaceDialectUID() {
+        return spaceDialectUID;
+    }
+
+    public void setSpaceDialectUID(String spaceDialectUID) {
+        this.spaceDialectUID = spaceDialectUID;
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getUid() {
+        return uid;
+    }
+
+    public void setUid(String uid) {
+        this.uid = uid;
+    }
+
+    public String getSecondUID() {
+        return secondUID;
+    }
+
+    public void setSecondUID(String secondUID) {
+        this.secondUID = secondUID;
+    }
+
+    public String getDialectUID() {
+        return dialectUID;
+    }
+
+    public void setDialectUID(String dialectUID) {
+        this.dialectUID = dialectUID;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getSalt() {
+        return salt;
+    }
+
+    public void setSalt(String salt) {
+        this.salt = salt;
+    }
+
+    public Short getHr() {
+        return hr;
+    }
+
+    public void setHr(Short hr) {
+        this.hr = hr;
+    }
+
+    public Short getPwdSecLevel() {
+        return pwdSecLevel;
+    }
+
+    public void setPwdSecLevel(Short pwdSecLevel) {
+        this.pwdSecLevel = pwdSecLevel;
+    }
+
+    public Long getLastLoginTime() {
+        return lastLoginTime;
+    }
+
+    public void setLastLoginTime(Long lastLoginTime) {
+        this.lastLoginTime = lastLoginTime;
+    }
+
+    public String getUu() {
+        return uu;
+    }
+
+    public void setUu(String uu) {
+        this.uu = uu;
+    }
+
+    public String getSpaceName() {
+        return spaceName;
+    }
+
+    public void setSpaceName(String spaceName) {
+        this.spaceName = spaceName;
+    }
+
+    public String getSpaceDomain() {
+        return spaceDomain;
+    }
+
+    public void setSpaceDomain(String spaceDomain) {
+        this.spaceDomain = spaceDomain;
+    }
+
+    /**
+     * get from sso token
+     *
+     * @return
+     */
+    public static UserView get() {
+        return SSO.data(UserView.class);
+    }
+}

+ 20 - 0
src/main/java/com/uas/account/sso/integration/exception/SSOException.java

@@ -0,0 +1,20 @@
+package com.uas.account.sso.integration.exception;
+
+/**
+ * Created by Pro1 on 2018/1/25.
+ */
+public class SSOException extends RuntimeException{
+    private static final long serialVersionUID = 1L;
+
+    public SSOException(String message) {
+        super(message);
+    }
+
+    public SSOException(Throwable throwable) {
+        super(throwable);
+    }
+
+    public SSOException(String message, Throwable throwable) {
+        super(message, throwable);
+    }
+}

+ 27 - 0
src/main/java/com/uas/account/sso/integration/function/Unchecked.java

@@ -0,0 +1,27 @@
+package com.uas.account.sso.integration.function;
+
+import java.util.Objects;
+import java.util.function.Function;
+
+/**
+ * Created by Pro1 on 2018/1/25.
+ */
+public class Unchecked {
+
+    public static <T, R> Function<T, R> of(UncheckedFunction<T, R> mapper) {
+        Objects.requireNonNull(mapper);
+        return t -> {
+            try {
+                return mapper.apply(t);
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+        };
+    }
+
+    @FunctionalInterface
+    public static interface UncheckedFunction<T, R> {
+        R apply(T t) throws Exception;
+    }
+
+}

+ 27 - 0
src/main/java/com/uas/account/sso/integration/util/CookieUtils.java

@@ -0,0 +1,27 @@
+package com.uas.account.sso.integration.util;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import java.util.Arrays;
+import java.util.Optional;
+
+/**
+ * Created by Pro1 on 2018/1/25.
+ */
+public class CookieUtils {
+
+    /**
+     * get cookie by name
+     *
+     * @param request
+     * @param cookieName
+     * @return
+     */
+    public static Cookie getCookie(HttpServletRequest request, String cookieName) {
+        return Optional.ofNullable(request.getCookies())
+                .map(Arrays::asList).get().stream()
+                .filter(cookie -> cookie.getName().equals(cookieName))
+                .findFirst().orElse(null);
+    }
+
+}

+ 39 - 0
src/main/java/com/uas/account/sso/integration/util/SSO.java

@@ -0,0 +1,39 @@
+package com.uas.account.sso.integration.util;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.uas.account.sso.integration.function.Unchecked;
+import com.uas.account.sso.integration.web.SSOToken;
+
+import java.util.Optional;
+
+/**
+ * Created by Pro1 on 2018/1/25.
+ */
+public final class SSO {
+
+    private static ObjectMapper mapper = new ObjectMapper();
+
+    private static ThreadLocal<SSOToken> token = new InheritableThreadLocal<SSOToken>();
+
+    public static SSOToken get() {
+        return token.get();
+    }
+
+    public static <T> T data(Class<T> targetCls) {
+        try {
+            return Optional.ofNullable(get()).map(Unchecked.of(v -> mapper.readValue(v.getData(), targetCls)))
+                    .orElseGet(null);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    public static void set(SSOToken ssoToken) {
+        token.set(ssoToken);
+    }
+
+    public static void clear() {
+        set(null);
+    }
+
+}

+ 87 - 0
src/main/java/com/uas/account/sso/integration/web/AbstractSSOInitializer.java

@@ -0,0 +1,87 @@
+package com.uas.account.sso.integration.web;
+
+import org.springframework.core.annotation.Order;
+import org.springframework.web.WebApplicationInitializer;
+import org.springframework.web.context.ContextLoaderListener;
+import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
+import org.springframework.web.filter.DelegatingFilterProxy;
+
+import javax.servlet.*;
+import java.util.EnumSet;
+
+/**
+ * Created by Pro1 on 2018/1/25.
+ */
+@Order(100)
+public abstract class AbstractSSOInitializer implements WebApplicationInitializer {
+
+    private final Class<?>[] configurationClasses;
+
+    /**
+     * default name for sso filter.
+     */
+    public static final String DEFAULT_FILTER_NAME = "ssoFilter";
+
+    private static final String SERVLET_CONTEXT_PREFIX = "org.springframework.web.servlet.FrameworkServlet.CONTEXT.";
+
+    protected AbstractSSOInitializer() {
+        this.configurationClasses = null;
+    }
+
+    protected AbstractSSOInitializer(Class<?>... configurationClasses) {
+        this.configurationClasses = configurationClasses;
+    }
+
+    @Override
+    public void onStartup(ServletContext servletContext) throws ServletException {
+        if (this.configurationClasses != null) {
+            AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
+            rootAppContext.register(this.configurationClasses);
+            servletContext.addListener(new ContextLoaderListener(rootAppContext));
+        }
+        insertSSOFilter(servletContext);
+    }
+
+    private void insertSSOFilter(ServletContext servletContext) {
+        String filterName = DEFAULT_FILTER_NAME;
+        DelegatingFilterProxy ssoFilter = new DelegatingFilterProxy(filterName);
+        String contextAttribute = getWebApplicationContextAttribute();
+        if (contextAttribute != null) {
+            ssoFilter.setContextAttribute(contextAttribute);
+        }
+        registerFilter(servletContext, true, filterName, ssoFilter);
+    }
+
+    private String getWebApplicationContextAttribute() {
+        String dispatcherServletName = getDispatcherWebApplicationContextSuffix();
+        if (dispatcherServletName == null) {
+            return null;
+        }
+        return SERVLET_CONTEXT_PREFIX + dispatcherServletName;
+    }
+
+    protected String getDispatcherWebApplicationContextSuffix() {
+        return null;
+    }
+
+    private void registerFilter(ServletContext servletContext,
+                                boolean insertBeforeOtherFilters, String filterName, Filter filter) {
+        FilterRegistration.Dynamic registration = servletContext.addFilter(filterName, filter);
+        if (registration == null) {
+            throw new IllegalStateException(
+                    "Duplicate Filter registration for '" + filterName
+                            + "'. Check to ensure the Filter is only configured once.");
+        }
+        registration.setAsyncSupported(isAsyncSessionSupported());
+        EnumSet<DispatcherType> dispatcherTypes = getSessionDispatcherTypes();
+        registration.addMappingForUrlPatterns(dispatcherTypes, !insertBeforeOtherFilters, "/*");
+    }
+
+    protected EnumSet<DispatcherType> getSessionDispatcherTypes() {
+        return EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR, DispatcherType.ASYNC);
+    }
+
+    protected boolean isAsyncSessionSupported() {
+        return true;
+    }
+}

+ 39 - 0
src/main/java/com/uas/account/sso/integration/web/SSOFilter.java

@@ -0,0 +1,39 @@
+package com.uas.account.sso.integration.web;
+
+import com.uas.account.sso.integration.util.SSO;
+import org.springframework.core.annotation.Order;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * Created by Pro1 on 2018/1/25.
+ */
+@Order(SSOFilter.DEFAULT_ORDER)
+public class SSOFilter extends OncePerRequestFilter {
+
+    public static final int DEFAULT_ORDER = Integer.MIN_VALUE + 50;
+
+    private final SSORepository repository;
+
+    public SSOFilter(SSORepository repository) {
+        this.repository = repository;
+    }
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
+        SSOToken token = repository.getToken(request);
+        if (null == token && repository.breakIfNull()) {
+            throw new ServletException("sso token is null");
+        }
+        SSO.set(token);
+        try {
+            filterChain.doFilter(request, response);
+        } finally {
+            SSO.clear();
+        }
+    }
+}

+ 47 - 0
src/main/java/com/uas/account/sso/integration/web/SSOProperties.java

@@ -0,0 +1,47 @@
+package com.uas.account.sso.integration.web;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * Created by Pro1 on 2018/1/25.
+ */
+@ConfigurationProperties("sso")
+public class SSOProperties {
+
+    @NotNull
+    private String secretKey;
+    @NotNull
+    private String cookieName = "uid";
+    private boolean breakIfNull = true;
+
+    public String getSecretKey() {
+        return secretKey;
+    }
+
+    public void setSecretKey(String secretKey) {
+        this.secretKey = secretKey;
+    }
+
+    public String getCookieName() {
+        return cookieName;
+    }
+
+    public void setCookieName(String cookieName) {
+        this.cookieName = cookieName;
+    }
+
+    /**
+     * 如果token为空,中断请求
+     *
+     * @return
+     */
+    public boolean isBreakIfNull() {
+        return breakIfNull;
+    }
+
+    public void setBreakIfNull(boolean breakIfNull) {
+        this.breakIfNull = breakIfNull;
+    }
+}

+ 43 - 0
src/main/java/com/uas/account/sso/integration/web/SSORepository.java

@@ -0,0 +1,43 @@
+package com.uas.account.sso.integration.web;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.uas.account.sso.integration.crypto.SSOEncrypt;
+import com.uas.account.sso.integration.util.CookieUtils;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * Created by Pro1 on 2018/1/25.
+ */
+public class SSORepository {
+
+    private final SSOProperties properties;
+
+    static final String CUT_SYMBOL = "#";
+
+    private ObjectMapper mapper = new ObjectMapper();
+
+    public SSORepository(SSOProperties properties) {
+        this.properties = properties;
+    }
+
+    protected SSOToken getToken(HttpServletRequest request) {
+        Cookie cookie = CookieUtils.getCookie(request, properties.getCookieName());
+        if (null != cookie) {
+            String jsonToken = cookie.getValue();
+            try {
+                jsonToken = SSOEncrypt.decrypt(jsonToken, properties.getSecretKey());
+                return mapper.readValue(jsonToken.split(CUT_SYMBOL)[0], SSOToken.class);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+
+        }
+        return null;
+    }
+
+    public boolean breakIfNull() {
+        return properties.isBreakIfNull();
+    }
+}

+ 113 - 0
src/main/java/com/uas/account/sso/integration/web/SSOToken.java

@@ -0,0 +1,113 @@
+package com.uas.account.sso.integration.web;
+
+import java.io.Serializable;
+
+/**
+ * Created by Pro1 on 2018/1/25.
+ */
+public class SSOToken implements Serializable{
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    /* 正常 */
+    public final static int FLAG_NORMAL = 0;
+
+    /* 缓存宕机 */
+    public final static int FLAG_CACHE_SHUT = 1;
+
+    /* 系统名称 */
+    private String app;
+
+    /* 登录类型 */
+    private Integer type;
+
+    /* 预留 */
+    private String data;
+
+    /* 用户 ID(长整型) */
+    private Long id;
+
+    /* 用户 ID(字符串类型,默认 fastjson 无值该参数不参与 json 序列化) */
+    private String uid;
+
+    /* 登录 IP */
+    private String ip;
+
+    /* 创建 token 当前系统时间 */
+    private long time = System.currentTimeMillis();
+
+    /**
+     * Token 状态标示
+     * <p>
+     * 默认正常执行
+     * </p>
+     */
+    private int flag = FLAG_NORMAL;
+
+    public String getApp() {
+        return app;
+    }
+
+    public void setApp(String app) {
+        this.app = app;
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getUid() {
+        return uid;
+    }
+
+    public void setUid(String uid) {
+        this.uid = uid;
+    }
+
+    public String getIp() {
+        return ip;
+    }
+
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    public int getFlag() {
+        return flag;
+    }
+
+    public void setFlag(int flag) {
+        this.flag = flag;
+    }
+
+    public long getTime() {
+        return time;
+    }
+
+    public void setTime(long time) {
+        this.time = time;
+    }
+
+    public Integer getType() {
+        return type;
+    }
+
+    public void setType(Integer type) {
+        this.type = type;
+    }
+
+    public String getData() {
+        return data;
+    }
+
+    public void setData(String data) {
+        this.data = data;
+    }
+}

+ 18 - 0
src/test/java/com/uas/account/test/CryptoTest.java

@@ -0,0 +1,18 @@
+package com.uas.account.test;
+
+import com.uas.account.sso.integration.crypto.SSOEncrypt;
+
+/**
+ * Created by Pro1 on 2018/1/26.
+ */
+public class CryptoTest {
+
+    public static void main(String[] args) throws Exception{
+        String uid = "4sjrtiHZOu3yCb4w-F30Ak3RfmupXyUBnSnugy1ac94KiVkR1M-Ue9zXFtbWADw2Rn4J1F4c15OMm1x4d5oE8OhSwALg7AiREkmq93yddqvKVMI-lBf2bH8BIM9yRwEXAxqU1aT89dp_nmVEYPW73Xrwjb7ADMEqUaacDq36cAxTChs3UGtQjz-9T6wS_ZanVS3ckhcXEh7t5jRA8MWj4A5aVzQsODoSPMBMGj2_cz945IJW5i9xcptQv530r212rlgtVcjg_p8J_ObGUsWtPpJG_2oOX9mC_uRdBjredfmyucDKhRdo-E0pmp_rUsHuJxvIiSaSm_HqvCpSnKrKl1mgqzF82oMUow0pTFWVTEUhr3Nu-KyrpgkxPxlmOK8Yh50fs52M-UuinOjRqySApPSAxw-iGzgiydiLMGVzo8rZAV_l43EP8KXXT5M0su7ODLBPH3TViBh9FoqfHAyfeThdPwf11V01HNTv77-zhvUEMu_CDDZgMf6wu7CcDTkR-luu5gPfs3cWJsrFLRoLHl7WOdWOwf4TH6-0RqLTKGl4jqp8dLWNBbRYe7G0-O0ZrHncIHgSGqy4dNCaSwZRkXhv4VONCw4vVxytnEYsqqvgSsfkPGkCtoIUdBY31n6xNFDs4p55ohDNVYHBZqJYYVkJw0bK62xdkbJzsUDDjtGfSXaHodMOJg..";
+        String key = "0taQcW073Z7G628g5H";
+        String plainText = "{\"app\":\"mall\",\"data\":\"{\\\"appId\\\":\\\"b2b\\\",\\\"dialectUID\\\":\\\"200040149\\\",\\\"id\\\":442919,\\\"lastLoginTime\\\":1516928950812,\\\"name\\\":\\\"应鹏\\\",\\\"password\\\":\\\"1681a29069c652e900273a8460c6f820\\\",\\\"pwdSecLevel\\\":1,\\\"salt\\\":\\\"200040149\\\",\\\"secondUID\\\":\\\"yingp@usoftchina.com\\\",\\\"spaceDialectUID\\\":\\\"10042875\\\",\\\"spaceId\\\":84793,\\\"spaceName\\\":\\\"深圳市优软商城科技有限公司\\\",\\\"spaceUID\\\":\\\"91440300MA5DC1WL1W\\\",\\\"uid\\\":\\\"13798490565\\\"}\",\"flag\":0,\"time\":1516930643160,\"uid\":\"13798490565\"}#dbea3589c3159621db381c3a74d161c2";
+        assert plainText.equals(SSOEncrypt.decrypt(uid, key));
+        assert uid.equals(SSOEncrypt.encrypt(plainText, key));
+    }
+
+}

+ 95 - 0
src/test/java/com/uas/account/test/MapperTest.java

@@ -0,0 +1,95 @@
+package com.uas.account.test;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Created by Pro1 on 2018/1/26.
+ */
+public class MapperTest {
+
+    private static ObjectMapper mapper = new ObjectMapper();
+
+    public static void main(String[] args) throws Exception{
+        String json = "{\"appId\":\"b2b\",\"spaceId\":83573,\"spaceUID\":\"8888888888\",\"spaceDialectUID\":\"1000001\",\"id\":438733,\"uid\":\"13798490565\",\"secondUID\":\"yingp@usoftchina.com\",\"dialectUID\":\"200040149\",\"name\":\"应鹏\",\"password\":\"1681a29069c652e900273a8460c6f820\",\"salt\":\"200040149\",\"hr\":null,\"pwdSecLevel\":1,\"lastLoginTime\":1516845020868,\"uu\":null,\"spaceName\":\"深圳市优软科技有限公司\",\"spaceDomain\":\"yrcs1\"}";
+        ExampleUser user = mapper.readValue(json, ExampleUser.class);
+        System.out.println(user.getAppId());
+    }
+
+    @JsonIgnoreProperties(ignoreUnknown = true)
+    static class ExampleUser {
+
+        private String appId;
+        private Long spaceId;
+        private String spaceUID;
+        private String spaceDialectUID;
+        private String uid;
+        private String secondUID;
+        private String dialectUID;
+        private String name;
+
+        public String getAppId() {
+            return appId;
+        }
+
+        public void setAppId(String appId) {
+            this.appId = appId;
+        }
+
+        public Long getSpaceId() {
+            return spaceId;
+        }
+
+        public void setSpaceId(Long spaceId) {
+            this.spaceId = spaceId;
+        }
+
+        public String getSpaceUID() {
+            return spaceUID;
+        }
+
+        public void setSpaceUID(String spaceUID) {
+            this.spaceUID = spaceUID;
+        }
+
+        public String getSpaceDialectUID() {
+            return spaceDialectUID;
+        }
+
+        public void setSpaceDialectUID(String spaceDialectUID) {
+            this.spaceDialectUID = spaceDialectUID;
+        }
+
+        public String getUid() {
+            return uid;
+        }
+
+        public void setUid(String uid) {
+            this.uid = uid;
+        }
+
+        public String getSecondUID() {
+            return secondUID;
+        }
+
+        public void setSecondUID(String secondUID) {
+            this.secondUID = secondUID;
+        }
+
+        public String getDialectUID() {
+            return dialectUID;
+        }
+
+        public void setDialectUID(String dialectUID) {
+            this.dialectUID = dialectUID;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+    }
+}