├── README.md ├── README_CN.md ├── api-gateway ├── .gitignore ├── Dockerfile ├── application.yml ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ └── main │ └── groovy │ └── me │ └── oraclebox │ └── api │ └── gateway │ ├── Application.groovy │ ├── PropertiesConfig.groovy │ ├── filter │ └── JwtFilter.groovy │ └── property │ └── ApplicationProperty.groovy ├── auth-service ├── .gitignore ├── Dockerfile ├── application.yml ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ └── main │ └── groovy │ └── me │ └── oraclebox │ └── auth │ └── service │ ├── Application.groovy │ ├── config │ ├── MongoConfig.groovy │ ├── PropertiesConfig.groovy │ └── RedisConfig.groovy │ ├── controller │ └── AuthController.groovy │ ├── exception │ └── GlobalControllerExceptionHandler.groovy │ ├── model │ ├── Account.groovy │ └── AccountRepository.groovy │ ├── property │ └── ApplicationProperty.groovy │ ├── restrofit │ ├── FacebookService.groovy │ └── ServiceFactory.java │ └── service │ └── AuthService.groovy ├── common ├── .gitignore ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ └── main │ └── groovy │ └── me │ └── oraclebox │ ├── exception │ └── AuthenticationException.groovy │ ├── facebook │ ├── AgeRange.java │ ├── Concentration.java │ ├── Degree.java │ ├── Education.java │ ├── Employer.java │ ├── FacebookAccount.java │ ├── Friends.java │ ├── Language.java │ ├── Location.java │ ├── School.java │ ├── Summary.java │ ├── Work.java │ ├── Year.java │ └── friends │ │ └── taggable │ │ ├── Cursors.java │ │ ├── Data.java │ │ ├── Datum.java │ │ ├── Paging.java │ │ ├── Picture.java │ │ └── TaggableFriends.java │ └── http │ ├── ResultModel.groovy │ └── ResultStatus.groovy ├── docs ├── overview.png ├── spring-boot-auth-microservice-auth.png └── temp.txt └── eureka-server ├── .gitignore ├── application.yml ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src └── main └── groovy └── me └── oraclebox └── EurekaApplication.groovy /README.md: -------------------------------------------------------------------------------- 1 | # spring-auth-microservice 2 | [中文版本](README_CN.md) 3 | 4 | Try implement authetication and api gateway microservices. 5 | 6 | ## Overview 7 | ### auth-service 8 | ``` 9 | Create a new user account by using username/password. 10 | Validate JWT token and retreive account information. 11 | ``` 12 | ### api-gateway 13 | ``` 14 | Route all incoming messages to corresponing service. 15 | Validate JWT token if request url containing **/private**. 16 | Reject all private APIs access if failed JWT validation. 17 | ``` 18 | ![overview](https://raw.githubusercontent.com/oraclebox/spring-auth-microservice/master/docs/spring-boot-auth-microservice-auth.png) 19 | 20 | ## Require Install 21 | ### Mongodb 22 | ``` 23 | docker run --name mongo -p 27017:27017 -d mongo 24 | ``` 25 | ### Redis 26 | ``` 27 | docker run --name redis -p 6379:6379 -d redis 28 | ``` 29 | ### Start spring-boot service 30 | #### auth-service 31 | ``` 32 | cd auth-service 33 | chmod +x gradlew 34 | ./gradlew clean build 35 | docker build -t localhost/auth-service:latest . 36 | docker run -it --name auth-service -p 9000:9000 -d localhost/auth-service 37 | ``` 38 | 39 | #### api-gateway 40 | ``` 41 | cd api-gateway 42 | chmod +x gradlew 43 | ./gradlew clean build 44 | docker build -t localhost/api-gateway:latest . 45 | docker run -it --name api-gateway -p 0.0.0.0:8888:8888 -d localhost/api-gateway 46 | ``` 47 | 48 | ## Create account by email 49 | POST http://localhost:8888/auth/v1/continuous with JSON 50 | ``` 51 | { 52 | "username": "Oraclebox", 53 | "email":"abc@gmail.com", 54 | "password":"pw31931836193@SEED" 55 | } 56 | ``` 57 | Response will give you JWT token 58 | ``` 59 | { 60 | "code": 200, 61 | "message": "Success", 62 | "token": "{JWT token.....}", 63 | "data": { 64 | "id": "5837f61325f710407084a13e", 65 | "username": "Oraclebox", 66 | "email": "abc@gmail.com" 67 | } 68 | } 69 | ``` 70 | 71 | ## Create account via facebook 72 | POST http://localhost:8888/auth/v1/continuous/facebook with Facebook token get from mobile/website login. 73 | ``` 74 | { 75 | "accessToken": "EAAIPVNssQLUBAPVvpaO1VuxmhCFErzEgKNhHp3Wb82qgWDa7CZBncdESEQWseqeqw3131ZAsjGnuuVmPaiZATZBtlZAZABpFxQEVQ0uvQclVGxCEPZAR2gU1sTsk7tLbdKK2P8TxHP551W92TYltcrnObZATxSW3123sdwe1MT8cIx7Os78TO52jELx0dnZBtmUuEZAUmfFAFYnwewQZewD" 76 | } 77 | ``` 78 | Response will give you JWT token and account 79 | ``` 80 | { 81 | "code": 200, 82 | "message": "Success", 83 | "token": {token}, 84 | "data": { 85 | "id": "58392ca031313712c88a0b84", 86 | "email": "oraclebox@gmail.com", 87 | "active": true, 88 | "socialId": "10153213359378475", 89 | "verified": true 90 | } 91 | } 92 | ``` 93 | 94 | ### Try to access private service 95 | ``` 96 | GET http://localhost:8888/auth/private/v1/greeting with HEARDER 97 | Authorization: Bearer {JWT token.....} 98 | Return 200 if success, 403 if token invalid. 99 | ``` 100 | ## Add New API to getway which require token validation. 101 | For example add http://localhost:9300/book/private/remove/{id} and http://localhost:9300/book/list 102 | 103 | api-gateway > application.yml 104 | ``` 105 | zuul: 106 | sensitiveHeaders: Authetication 107 | routes: 108 | auth: #authetication service 109 | path: /auth/** 110 | url: http://localhost:9000/auth 111 | book: #authetication service 112 | path: /book/** 113 | url: http://localhost:9300/book 114 | ``` 115 | The can access them via API Gateway 116 | 117 | http://localhost:8888/book/private/remove/{id} (Require JWT header because url contain /private) 118 | 119 | http://localhost:8888/book/list 120 | 121 | 122 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | # spring-auth-microservice 2 | 嘗試實現用於RESTFUL風格的簡單身份驗證和api網關的微服務。 3 | 4 | ## 概述 5 | ### auth-service 服務負責 6 | ``` 7 | 使用EMAIL/密碼來創建新的帳戶。 8 | 使用Facebook Token來創建新的帳戶。 9 | 每次帳戶登入檢查密碼並產生新的JWT。 10 | 容許其他服務驗證JWT真偽並返回帳戶信息。 11 | 管理JWT的期限 12 | ``` 13 | ### api-gateway 14 | ``` 15 | 將所有傳入的請求路由到相應的服務。 16 | 如果請求URL路徑包含** /private **,則在路由之前向auth-service請求驗證JWT。 17 | 如果JWT驗證失敗,則拒絕API訪問。 18 | ``` 19 | ![overview](https://raw.githubusercontent.com/oraclebox/spring-auth-microservice/master/docs/spring-boot-auth-microservice-auth.png) 20 | 21 | ## 需要安裝的組件(以下經Docker安裝) 22 | ### Mongodb 23 | ``` 24 | docker run --name mongo -p 27017:27017 -d mongo 25 | ``` 26 | ### Redis 27 | ``` 28 | docker run --name redis -p 6379:6379 -d redis 29 | ``` 30 | ### eureka-server 31 | ``` 32 | cd eureka-server 33 | chmod +x gradlew 34 | ./gradlew clean build 35 | docker build -t localhost/eureka-server:latest . 36 | docker run -it --net=host --name eureka-server -p 8761:8761 -d localhost/eureka-server 37 | ``` 38 | ### auth-service 39 | ``` 40 | cd auth-service 41 | chmod +x gradlew 42 | ./gradlew clean build 43 | docker build -t localhost/auth-service:latest . 44 | docker run -it --net=host --name auth-service -p 9000:9000 -d localhost/auth-service 45 | ``` 46 | ### api-gateway 47 | ``` 48 | cd api-gateway 49 | chmod +x gradlew 50 | ./gradlew clean build 51 | docker build -t localhost/api-gateway:latest . 52 | docker run -it --net=host --name api-gateway -p 0.0.0.0:8888:8888 -d localhost/api-gateway 53 | ``` 54 | 55 | 56 | 57 | ## API 58 | ### 用電子郵件創建帳戶 59 | POST http://localhost:8888/auth/v1/continuous with JSON 60 | ``` 61 | { 62 | "username": "Oraclebox", 63 | "email":"abc@gmail.com", 64 | "password":"pw31931836193@SEED" 65 | } 66 | ``` 67 | 返回會給你JWT作為其他私有服務登入的TOKEN及帳戶信息 68 | ``` 69 | { 70 | "code": 200, 71 | "message": "Success", 72 | "token": "{JWT}", 73 | "data": { 74 | "id": "5837f61325f710407084a13e", 75 | "username": "Oraclebox", 76 | "email": "abc@gmail.com" 77 | } 78 | } 79 | ``` 80 | 81 | ### 用電子郵件登入 82 | POST http://localhost:8888/auth/v1/continuous with JSON 83 | ``` 84 | { 85 | "email":"abc@gmail.com", 86 | "password":"pw31931836193@SEED" 87 | } 88 | ``` 89 | 返回會給你已更新的JWT作為其他私有服務登入的TOKEN及帳戶信息 90 | ``` 91 | { 92 | "code": 200, 93 | "message": "Success", 94 | "token": "{JWT}", 95 | "data": { 96 | "id": "5837f61325f710407084a13e", 97 | "username": "Oraclebox", 98 | "email": "abc@gmail.com" 99 | } 100 | } 101 | ``` 102 | ## 通過Facebook創建帳戶, 手機/網站用Facebook的SDK作客戶端的登入,並把FACEBOOK TOKEN 發過來。 103 | POST http://localhost:8888/auth/v1/continuous/facebook with Facebook token get from mobile/website login. 104 | ``` 105 | { 106 | "accessToken": "EAAIPVNssQLUBAPVvpaO1VuxmhCFErzEgKNhHp3Wb82qgWDa7CZBncdESEQWseqeqw3131ZAsjGnuuVmPaiZATZBtlZAZABpFxQEVQ0uvQclVGxCEPZAR2gU1sTsk7tLbdKK2P8TxHP551W92TYltcrnObZATxSW3123sdwe1MT8cIx7Os78TO52jELx0dnZBtmUuEZAUmfFAFYnwewQZewD" 107 | } 108 | ``` 109 | auth-service會向FACEBOOK請求用戶資訊以确保accessToken有效,如果是第一次登入建立帳戶,返回會給你已更新的JWT作為其他私有服務登入的TOKEN及帳戶信息 110 | ``` 111 | { 112 | "code": 200, 113 | "message": "Success", 114 | "token": {JWT}, 115 | "data": { 116 | "id": "58392ca031313712c88a0b84", 117 | "email": "oraclebox@gmail.com", 118 | "active": true, 119 | "socialId": "10153213359378475", 120 | "verified": true 121 | } 122 | } 123 | ``` 124 | 125 | ### 嘗試訪問私人服務(必須login的服務 URL的路徑可含/private) 126 | 把返回的{JWT}放到HTTP HEADER之中,格式是 Key="Authorization" value="Bearer {JWT}" 127 | ``` 128 | GET http://localhost:8888/auth/private/v1/greeting with HEARDER 129 | Authorization: Bearer {JWT} 130 | Return 200 if success, 403 if token invalid. 131 | ``` 132 | ## 添加新的API(需要驗證)到getway。 133 | 例如添加 http://localhost:9300/book/private/remove/{id} 及 http://localhost:9300/book/list 134 | 135 | 其中http://localhost:9300/book/private/remove/{id} 需要{JWT} 136 | 137 | api-gateway > application.yml 138 | ``` 139 | zuul: 140 | sensitiveHeaders: Authetication 141 | routes: 142 | auth: #authetication service 143 | path: /auth/** 144 | serviceId: auth-serivce 145 | book: #authetication service 146 | path: /book/** 147 | url: http://localhost:9300/book 148 | ``` 149 | 可以通過API網關訪問它們 150 | 151 | http://localhost:8888/book/private/remove/{id} (因為路徑包括/private網關會請求auth-service驗證才會向下轉發) 152 | 153 | http://localhost:8888/book/list 154 | 155 | 另如果book service 加入 Eureka DiscoveryClient,可以先向Eureka注冊自己,然后在api-gateway使用serviceId注冊服務。 156 | 157 | -------------------------------------------------------------------------------- /api-gateway/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .idea/ 3 | .gradle/ 4 | -------------------------------------------------------------------------------- /api-gateway/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM anapsix/alpine-java:8 2 | RUN mkdir /application 3 | RUN mkdir -p /application/logs 4 | COPY build/libs/api-gateway-0.0.1-SNAPSHOT.jar /application/api-gateway.jar 5 | COPY application.yml /application/application.yml 6 | WORKDIR /application 7 | ENTRYPOINT ["java","-jar"] 8 | CMD ["api-gateway.jar"] 9 | EXPOSE 8888 10 | -------------------------------------------------------------------------------- /api-gateway/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: api-gateway 4 | server: 5 | port: 8888 6 | tomcat: 7 | protocol_header: x-forwarded-proto 8 | use-forward-headers: true 9 | #endpoints: 10 | # restart: 11 | # enabled: true 12 | # shutdown: 13 | # enabled: true 14 | # health: 15 | # sensitive: false 16 | eureka: 17 | client: 18 | healthcheck: 19 | enabled: true 20 | # registerWithEureka: true 21 | # fetchRegistry: true 22 | serviceUrl: 23 | defaultZone: http://localhost:8761/eureka/ 24 | instance: 25 | leaseRenewalIntervalInSeconds: 10 26 | leaseExpirationDurationInSeconds: 30 27 | preferIpAddress: true 28 | zuul: 29 | sensitiveHeaders: Authetication 30 | routes: 31 | auth: #authetication service 32 | path: /auth/** 33 | serviceId: auth-service 34 | strip-prefix: false 35 | #url: http://localhost:9000 36 | ribbon: 37 | eureka: 38 | enabled: true 39 | application: 40 | authServiceUrl: http://auth-service/auth/v1/me 41 | -------------------------------------------------------------------------------- /api-gateway/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | springBootVersion = '1.4.2.RELEASE' 4 | } 5 | repositories { 6 | mavenCentral() 7 | maven { url "https://repo.spring.io/snapshot" } 8 | maven { url "https://repo.spring.io/milestone" } 9 | } 10 | dependencies { 11 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 12 | classpath "io.spring.gradle:dependency-management-plugin:0.5.6.RELEASE" 13 | } 14 | } 15 | 16 | allprojects { 17 | apply plugin: 'groovy' 18 | apply plugin: 'java' 19 | apply plugin: 'org.springframework.boot' 20 | sourceCompatibility = 1.8 21 | targetCompatibility = 1.8 22 | } 23 | 24 | 25 | jar { 26 | baseName = 'api-gateway' 27 | version = '0.0.1-SNAPSHOT' 28 | } 29 | 30 | repositories { 31 | mavenCentral() 32 | maven { url "https://repo.spring.io/snapshot" } 33 | maven { url "https://repo.spring.io/milestone" } 34 | } 35 | 36 | 37 | dependencies { 38 | compile('org.codehaus.groovy:groovy-all:2.3.11') 39 | compile project(':common') 40 | // https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-zuul 41 | compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-zuul', version: '1.2.3.RELEASE' 42 | compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-eureka', version: '1.2.3.RELEASE' 43 | compile("org.springframework.boot:spring-boot-starter-web:${springBootVersion}") 44 | testCompile("org.springframework.boot:spring-boot-starter-test:${springBootVersion}") 45 | } 46 | 47 | //dependencyManagement { 48 | // imports { 49 | // mavenBom "org.springframework.cloud:spring-cloud-dependencies:Camden.BUILD-SNAPSHOT" 50 | // } 51 | //} 52 | -------------------------------------------------------------------------------- /api-gateway/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oraclebox/spring-boot-auth-microservice/81ddb3dfc52352af4b45c4a944e74e5a7ef6d0c8/api-gateway/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /api-gateway/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Nov 25 14:16:24 CST 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.1-all.zip 7 | -------------------------------------------------------------------------------- /api-gateway/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 165 | if [[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]]; then 166 | cd "$(dirname "$0")" 167 | fi 168 | 169 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 170 | -------------------------------------------------------------------------------- /api-gateway/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /api-gateway/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'api-gateway' 2 | 3 | include ':common' 4 | project(':common').projectDir = new File(settingsDir, '../common') -------------------------------------------------------------------------------- /api-gateway/src/main/groovy/me/oraclebox/api/gateway/Application.groovy: -------------------------------------------------------------------------------- 1 | package me.oraclebox.api.gateway 2 | 3 | import me.oraclebox.api.gateway.filter.JwtFilter 4 | import org.springframework.boot.SpringApplication 5 | import org.springframework.boot.autoconfigure.SpringBootApplication 6 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient 7 | import org.springframework.cloud.client.loadbalancer.LoadBalanced 8 | import org.springframework.cloud.netflix.zuul.EnableZuulProxy 9 | import org.springframework.context.annotation.Bean 10 | import org.springframework.web.client.RestTemplate 11 | 12 | @EnableZuulProxy 13 | @SpringBootApplication 14 | class Application { 15 | 16 | public static void main(String[] args) { 17 | SpringApplication.run(Application.class, args); 18 | } 19 | 20 | @Bean 21 | public JwtFilter jwtFilter() { 22 | return new JwtFilter(); 23 | } 24 | 25 | @LoadBalanced 26 | @Bean 27 | RestTemplate restTemplate() { 28 | return new RestTemplate(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /api-gateway/src/main/groovy/me/oraclebox/api/gateway/PropertiesConfig.groovy: -------------------------------------------------------------------------------- 1 | package me.oraclebox.api.gateway 2 | 3 | import me.oraclebox.api.gateway.property.ApplicationProperty 4 | import org.springframework.boot.context.properties.EnableConfigurationProperties 5 | import org.springframework.context.annotation.Configuration 6 | 7 | /** 8 | * Created by oraclebox on 12/4/2016. 9 | */ 10 | @Configuration 11 | @EnableConfigurationProperties([ApplicationProperty.class]) 12 | class PropertiesConfig { 13 | } 14 | -------------------------------------------------------------------------------- /api-gateway/src/main/groovy/me/oraclebox/api/gateway/filter/JwtFilter.groovy: -------------------------------------------------------------------------------- 1 | package me.oraclebox.api.gateway.filter 2 | 3 | import com.netflix.zuul.ZuulFilter 4 | import com.netflix.zuul.context.RequestContext 5 | import me.oraclebox.api.gateway.property.ApplicationProperty 6 | import me.oraclebox.http.ResultModel 7 | import org.slf4j.Logger 8 | import org.slf4j.LoggerFactory 9 | import org.springframework.beans.factory.annotation.Autowired 10 | import org.springframework.http.HttpEntity 11 | import org.springframework.http.HttpHeaders 12 | import org.springframework.http.HttpMethod 13 | import org.springframework.web.client.HttpServerErrorException 14 | import org.springframework.web.client.RestTemplate 15 | 16 | import javax.servlet.http.HttpServletRequest 17 | 18 | /** 19 | * Filter use to validate JWT token in request header if path is start from /private/ 20 | * 篩選器用於對每一個開始為/private的HTTP請求,驗證標頭中的JWT 21 | * Created by oraclebox on 11/24/2016. 22 | */ 23 | class JwtFilter extends ZuulFilter { 24 | 25 | @Autowired 26 | RestTemplate restTemplate; 27 | @Autowired 28 | ApplicationProperty property; 29 | 30 | private static Logger log = LoggerFactory.getLogger(JwtFilter.class); 31 | 32 | @Override 33 | String filterType() { 34 | return "pre"; 35 | } 36 | 37 | @Override 38 | int filterOrder() { 39 | return 0; 40 | } 41 | 42 | @Override 43 | boolean shouldFilter() { 44 | return true; 45 | } 46 | 47 | @Override 48 | Object run() { 49 | RequestContext ctx = RequestContext.getCurrentContext(); 50 | HttpServletRequest request = ctx.getRequest(); 51 | log.info(String.format("%s request to %s", request.getMethod(), request.getRequestURL().toString())); 52 | 53 | // Require check JWT header 54 | if (request.getRequestURL().toString().indexOf("/private/") > 0) { 55 | final String authHeader = request.getHeader("Authorization"); 56 | if (authHeader == null || !authHeader.startsWith("Bearer ")) { 57 | log.warn("Missing Authorization header and token."); 58 | ctx.setSendZuulResponse(false); 59 | ctx.setResponseStatusCode(403); 60 | return null; 61 | } 62 | 63 | try { 64 | HttpHeaders headers = new HttpHeaders(); 65 | headers.set("Authorization", authHeader); 66 | HttpEntity entity = new HttpEntity(headers); 67 | 68 | HttpEntity response = restTemplate.exchange( 69 | property.authServiceUrl, HttpMethod.GET, entity, ResultModel.class); 70 | }catch(Exception e){ 71 | e.printStackTrace(); 72 | log.error("Cannot validate token: "+authHeader+" from "+property.authServiceUrl); 73 | ctx.setSendZuulResponse(false); 74 | ctx.setResponseStatusCode(403); 75 | } 76 | log.debug(property.authServiceUrl); 77 | } 78 | return null; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /api-gateway/src/main/groovy/me/oraclebox/api/gateway/property/ApplicationProperty.groovy: -------------------------------------------------------------------------------- 1 | package me.oraclebox.api.gateway.property 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties 4 | 5 | @ConfigurationProperties(prefix = "application") 6 | class ApplicationProperty { 7 | String authServiceUrl; 8 | } 9 | -------------------------------------------------------------------------------- /auth-service/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .idea/ 3 | .gradle/ 4 | -------------------------------------------------------------------------------- /auth-service/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM anapsix/alpine-java:8 2 | RUN mkdir /application 3 | RUN mkdir -p /application/logs 4 | COPY build/libs/auth-service-0.0.1-SNAPSHOT.jar /application/auth-service.jar 5 | COPY application.yml /application/application.yml 6 | WORKDIR /application 7 | ENTRYPOINT ["java","-jar"] 8 | CMD ["auth-service.jar"] 9 | EXPOSE 9000 10 | -------------------------------------------------------------------------------- /auth-service/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9000 3 | display-name: auth-service 4 | compression: 5 | enabled: off 6 | mime-types: application/json,application/xml,text/html,text/xml,text/plain 7 | tomcat: 8 | protocol_header: x-forwarded-proto 9 | use-forward-headers: true 10 | spring: 11 | application: 12 | name: auth-service 13 | # Database 14 | data: 15 | mongodb: 16 | uri: mongodb://localhost:27017/oraclebox 17 | # Redis 18 | redis: 19 | database: 2 20 | host: localhost 21 | port: 6379 22 | #password: 23 | timeout: 60000 24 | pool: 25 | max-active: 10 26 | max-idle: 10 27 | max-wait: -1 28 | min-idle: 2 29 | eureka: 30 | client: 31 | serviceUrl: 32 | defaultZone: http://localhost:8761/eureka/ 33 | instance: 34 | leaseRenewalIntervalInSeconds: 10 35 | leaseExpirationDurationInSeconds: 30 36 | preferIpAddress: true 37 | instance-id: ${spring.cloud.client.ipAddress}:${server.port} 38 | application: 39 | jwtTTL: 7776000000 #90 days (ms) 40 | jwtPhase: 3182318hjbdqsugdusagvjcvuy*&@T*12tuGJDUYASGDUY 41 | jwtIssuer: oraclebox -------------------------------------------------------------------------------- /auth-service/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | springBootVersion = '1.4.2.RELEASE' 4 | } 5 | repositories { 6 | mavenCentral() 7 | maven { url "https://repo.spring.io/snapshot" } 8 | maven { url "https://repo.spring.io/milestone" } 9 | } 10 | dependencies { 11 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 12 | classpath "io.spring.gradle:dependency-management-plugin:0.5.6.RELEASE" 13 | } 14 | } 15 | 16 | 17 | allprojects { 18 | apply plugin: 'groovy' 19 | apply plugin: 'java' 20 | apply plugin: 'org.springframework.boot' 21 | apply plugin: "io.spring.dependency-management" 22 | sourceCompatibility = 1.8 23 | targetCompatibility = 1.8 24 | } 25 | 26 | jar { 27 | baseName = 'auth-service' 28 | version = '0.0.1-SNAPSHOT' 29 | } 30 | 31 | repositories { 32 | mavenCentral() 33 | maven { url "https://repo.spring.io/snapshot" } 34 | maven { url "https://repo.spring.io/milestone" } 35 | } 36 | 37 | dependencies { 38 | compile project(':common') 39 | compile('org.codehaus.groovy:groovy-all:2.3.11') 40 | compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-eureka', version: '1.2.3.RELEASE' 41 | //compile("org.springframework.boot:spring-boot-starter-data-jpa:${springBootVersion}") 42 | compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-mongodb', version: "${springBootVersion}" 43 | compile("org.springframework.boot:spring-boot-starter:${springBootVersion}"); 44 | compile("org.springframework.boot:spring-boot-starter-web:${springBootVersion}") 45 | // https://mvnrepository.com/artifact/org.springframework.security/spring-security-crypto 46 | compile group: 'org.springframework.security', name: 'spring-security-crypto', version: '4.2.0.RELEASE' 47 | compile("org.springframework.boot:spring-boot-starter-redis:${springBootVersion}") 48 | // https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-joda 49 | compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-joda', version: '2.8.5' 50 | // JWT 51 | compile group: 'io.jsonwebtoken', name: 'jjwt', version: '0.7.0' 52 | 53 | // https://mvnrepository.com/artifact/io.reactivex/rxjava 54 | compile group: 'io.reactivex', name: 'rxjava', version: '1.1.10' 55 | // Retrofit2 56 | compile group: 'com.squareup.retrofit2', name: 'retrofit', version: '2.1.0' 57 | compile group: 'com.squareup.retrofit2', name: 'converter-gson', version: '2.1.0' 58 | compile group: 'com.squareup.retrofit2', name: 'adapter-rxjava', version: '2.1.0' 59 | 60 | testCompile("org.springframework.boot:spring-boot-starter-test:${springBootVersion}") 61 | 62 | 63 | testCompile group: 'junit', name: 'junit', version: '4.11' 64 | } 65 | -------------------------------------------------------------------------------- /auth-service/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oraclebox/spring-boot-auth-microservice/81ddb3dfc52352af4b45c4a944e74e5a7ef6d0c8/auth-service/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /auth-service/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Nov 25 08:46:13 CST 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.1-all.zip 7 | -------------------------------------------------------------------------------- /auth-service/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 165 | if [[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]]; then 166 | cd "$(dirname "$0")" 167 | fi 168 | 169 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 170 | -------------------------------------------------------------------------------- /auth-service/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /auth-service/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'auth-service' 2 | 3 | include ':common' 4 | project(':common').projectDir = new File(settingsDir, '../common') 5 | 6 | -------------------------------------------------------------------------------- /auth-service/src/main/groovy/me/oraclebox/auth/service/Application.groovy: -------------------------------------------------------------------------------- 1 | package me.oraclebox.auth.service 2 | 3 | import org.springframework.boot.SpringApplication 4 | import org.springframework.boot.autoconfigure.SpringBootApplication 5 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient 6 | import org.springframework.context.annotation.Bean 7 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder 8 | import org.springframework.security.crypto.password.PasswordEncoder 9 | 10 | @EnableDiscoveryClient 11 | @SpringBootApplication 12 | class Application { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(Application.class, args); 16 | } 17 | 18 | @Bean 19 | public PasswordEncoder passwordEncoder() { 20 | PasswordEncoder encoder = new BCryptPasswordEncoder(); 21 | return encoder; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /auth-service/src/main/groovy/me/oraclebox/auth/service/config/MongoConfig.groovy: -------------------------------------------------------------------------------- 1 | package me.oraclebox.auth.service.config 2 | 3 | import org.springframework.context.annotation.Configuration 4 | 5 | /** 6 | * 7 | * Created by oraclebox on 2/10/2016. 8 | */ 9 | @Configuration 10 | class MongoConfig { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /auth-service/src/main/groovy/me/oraclebox/auth/service/config/PropertiesConfig.groovy: -------------------------------------------------------------------------------- 1 | package me.oraclebox.auth.service.config 2 | 3 | import me.oraclebox.auth.service.property.ApplicationProperty 4 | import org.springframework.boot.context.properties.EnableConfigurationProperties 5 | import org.springframework.context.annotation.Configuration 6 | 7 | /** 8 | * Created by oraclebox on 12/4/2016. 9 | */ 10 | @Configuration 11 | @EnableConfigurationProperties([ApplicationProperty.class]) 12 | class PropertiesConfig { 13 | } 14 | -------------------------------------------------------------------------------- /auth-service/src/main/groovy/me/oraclebox/auth/service/config/RedisConfig.groovy: -------------------------------------------------------------------------------- 1 | package me.oraclebox.auth.service.config 2 | 3 | import com.fasterxml.jackson.annotation.JsonAutoDetect 4 | import com.fasterxml.jackson.annotation.PropertyAccessor 5 | import com.fasterxml.jackson.databind.ObjectMapper 6 | import com.fasterxml.jackson.datatype.joda.JodaModule 7 | import org.springframework.cache.annotation.EnableCaching 8 | import org.springframework.context.annotation.Bean 9 | import org.springframework.context.annotation.Configuration 10 | import org.springframework.data.redis.connection.RedisConnectionFactory 11 | import org.springframework.data.redis.core.StringRedisTemplate 12 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer 13 | 14 | @Configuration 15 | @EnableCaching 16 | public class RedisConfig { 17 | 18 | @Bean 19 | public StringRedisTemplate template(RedisConnectionFactory factory) { 20 | ObjectMapper om = new ObjectMapper(); 21 | om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); 22 | om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); 23 | om.registerModule(new JodaModule()); 24 | 25 | Jackson2JsonRedisSerializer serializer = new 26 | Jackson2JsonRedisSerializer<>(Object.class); 27 | serializer.setObjectMapper(om); 28 | 29 | StringRedisTemplate template = new StringRedisTemplate(factory); 30 | template.setValueSerializer(serializer); 31 | template.setHashValueSerializer(serializer); 32 | template.afterPropertiesSet(); 33 | 34 | return template; 35 | } 36 | } -------------------------------------------------------------------------------- /auth-service/src/main/groovy/me/oraclebox/auth/service/controller/AuthController.groovy: -------------------------------------------------------------------------------- 1 | package me.oraclebox.auth.service.controller 2 | 3 | import me.oraclebox.auth.service.model.Account 4 | import me.oraclebox.auth.service.service.AuthService 5 | import me.oraclebox.exception.AuthenticationException 6 | import me.oraclebox.facebook.FacebookAccount 7 | import me.oraclebox.http.ResultModel 8 | import org.springframework.beans.factory.annotation.Autowired 9 | import org.springframework.http.HttpStatus 10 | import org.springframework.http.ResponseEntity 11 | import org.springframework.util.Assert 12 | import org.springframework.web.bind.annotation.RequestBody 13 | import org.springframework.web.bind.annotation.RequestMapping 14 | import org.springframework.web.bind.annotation.RequestMethod 15 | import org.springframework.web.bind.annotation.RestController 16 | 17 | import javax.servlet.http.HttpServletRequest 18 | 19 | /** 20 | * 處理注冊或登入請求 21 | * Created by oraclebox@gmail.com on 11/25/2016. 22 | */ 23 | @RestController 24 | @RequestMapping("/auth") 25 | class AuthController { 26 | 27 | @Autowired 28 | AuthService service; 29 | /** 30 | * 處理用戶名稱/密碼的注冊或登入請求 31 | * 首次請求創建帳戶並返回JWT 32 | * 其后更新JWT並返回 33 | *{* "username": "userABC", 34 | * "email":"userABC@gmail.com", 35 | * "password":"312313123213123123213" 36 | *}*/ 37 | @RequestMapping(value = "/v1/continuous", method = RequestMethod.POST) 38 | ResponseEntity continuousByUsernameAndPassword(@RequestBody Map json) { 39 | Assert.isTrue(json != null && json.size() > 0, "Missing json."); 40 | Assert.isTrue(json.containsKey("email"), "Missing email."); 41 | Assert.isTrue(json.containsKey("password"), "Missing password."); 42 | 43 | String email = json.get("email").toString(); 44 | Account account = null; 45 | String jwt = null; 46 | 47 | // Find account with same username, check password 48 | if ((account = service.byEmail(email)) != null) { 49 | // Validate 50 | if (service.validatePassword(json.get("password").toString(), account)) { 51 | jwt = service.generateJWT(account); 52 | } else { 53 | throw new AuthenticationException("Username/Password is not correct."); 54 | } 55 | } 56 | // Fist time sign up 57 | else { 58 | account = service.save(new Account( 59 | username: json.get("username"), 60 | password: service.encryptPassword(json.get("password").toString()), 61 | email: email, 62 | via: ["email"], 63 | active: true)); 64 | jwt = service.generateJWT(account); 65 | //TODO Email verification 66 | } 67 | return new ResponseEntity>(ResultModel._200("Success", jwt, account), HttpStatus.OK); 68 | } 69 | 70 | @RequestMapping(value = "/v1/continuous/facebook", method = RequestMethod.POST) 71 | ResponseEntity continuousFacebook(@RequestBody Map json) { 72 | Assert.isTrue(json != null && json.size() > 0, "Missing json."); 73 | Assert.isTrue(json.containsKey("accessToken"), "Missing facebook accessToken in json."); 74 | String accessToken = (String) json.get("accessToken"); 75 | 76 | // Call facebook /me 77 | FacebookAccount fbAccount = service.facebookMe(accessToken).toBlocking().first(); 78 | 79 | String jwt = null; 80 | Account account = null; 81 | 82 | // Find existing account registered by email, add facebook information 83 | if ((account = service.byEmail(fbAccount.email)) != null && account.via == ["email"]) { 84 | account.via.add("facebook"); 85 | account.socialId = fbAccount.id; 86 | account.verified = true; 87 | service.save(account); 88 | } 89 | // Create an new account if cannot find via social account id. 90 | else if ((account = service.bySocialId(fbAccount.id)) == null) { 91 | account = service.save(new Account( 92 | username: fbAccount.name, 93 | socialId: fbAccount.id, 94 | email: fbAccount.email, 95 | verified: true, 96 | via: ["facebook"], 97 | active: true)); 98 | } 99 | // Renew JWT token each time login 100 | jwt = service.generateJWT(account); 101 | 102 | return new ResponseEntity>(ResultModel._200("Success", jwt, account), HttpStatus.OK); 103 | } 104 | 105 | /** 106 | * 請求標頭中取出JWT,驗証並在有效的情況下則返回帳戶資料 107 | * Validate JWT token in request header and return account if valid. 108 | */ 109 | @RequestMapping(value = "/v1/me", method = RequestMethod.GET) 110 | ResponseEntity getAccount(HttpServletRequest request) { 111 | String token = getJWT(request); 112 | Account account = service.parseJWT(token); 113 | return new ResponseEntity>(ResultModel._200("Success", token, account), HttpStatus.OK); 114 | } 115 | 116 | @RequestMapping(value = "/private/v1/greeting", method = RequestMethod.GET) 117 | ResponseEntity greeting(HttpServletRequest request) { 118 | return new ResponseEntity>(ResultModel._200("Success", "Hello World!!!"), HttpStatus.OK); 119 | } 120 | 121 | String getJWT(HttpServletRequest request) { 122 | final String authHeader = request.getHeader("Authorization"); 123 | if (authHeader == null || !authHeader.startsWith("Bearer ")) { 124 | throw new AuthenticationException("Missing Authorization header and token."); 125 | } 126 | return authHeader.substring(7); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /auth-service/src/main/groovy/me/oraclebox/auth/service/exception/GlobalControllerExceptionHandler.groovy: -------------------------------------------------------------------------------- 1 | package me.oraclebox.auth.service.exception 2 | 3 | import me.oraclebox.exception.AuthenticationException 4 | import me.oraclebox.http.ResultModel 5 | import org.slf4j.Logger 6 | import org.slf4j.LoggerFactory 7 | import org.springframework.http.HttpStatus 8 | import org.springframework.http.ResponseEntity 9 | import org.springframework.web.bind.annotation.ControllerAdvice 10 | import org.springframework.web.bind.annotation.ExceptionHandler 11 | import org.springframework.web.bind.annotation.ResponseBody 12 | 13 | /** 14 | * Global exception handler 15 | * Created by ROGER CHAN on 14/9/2016. 16 | */ 17 | @ControllerAdvice 18 | class GlobalControllerExceptionHandler { 19 | 20 | private final Logger L = LoggerFactory.getLogger(this.getClass()); 21 | 22 | 23 | @ExceptionHandler(AuthenticationException.class) 24 | @ResponseBody 25 | ResponseEntity handleException(AuthenticationException ex) { 26 | def id = UUID.randomUUID().toString(); // case id 27 | L.warn("[" + id + "] " + ex.getMessage()); 28 | return new ResponseEntity<>(ResultModel._403(ex.getMessage(), null), HttpStatus.FORBIDDEN); 29 | } 30 | 31 | @ExceptionHandler(Exception.class) 32 | @ResponseBody 33 | ResponseEntity handleException(Exception ex) { 34 | def id = UUID.randomUUID().toString(); // case id 35 | L.error("[" + id + "] " + ex.getMessage()); 36 | return new ResponseEntity<>(ResultModel._500(ex.getMessage(), null), HttpStatus.INTERNAL_SERVER_ERROR); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /auth-service/src/main/groovy/me/oraclebox/auth/service/model/Account.groovy: -------------------------------------------------------------------------------- 1 | package me.oraclebox.auth.service.model 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore 4 | import com.fasterxml.jackson.annotation.JsonInclude 5 | import com.fasterxml.jackson.annotation.JsonProperty 6 | import com.fasterxml.jackson.annotation.JsonPropertyOrder 7 | import org.springframework.data.mongodb.core.mapping.Document 8 | 9 | @Document 10 | @JsonInclude(JsonInclude.Include.NON_NULL) 11 | @JsonPropertyOrder([ 12 | "id", 13 | "username", 14 | "password", 15 | "email", 16 | "active" 17 | ]) 18 | class Account { 19 | @JsonProperty("id") 20 | String id; 21 | @JsonProperty("socialId") 22 | String socialId; 23 | @JsonProperty("username") 24 | String username; 25 | @JsonProperty(value = "password", access = JsonProperty.Access.WRITE_ONLY) 26 | String password; 27 | @JsonProperty("email") 28 | String email; 29 | @JsonProperty("active") 30 | Boolean active; 31 | @JsonProperty("verified") // Email verification passed 32 | Boolean verified; 33 | @JsonIgnore 34 | List via = []; 35 | @JsonIgnore 36 | Map additionalProperties = new HashMap(); 37 | } 38 | -------------------------------------------------------------------------------- /auth-service/src/main/groovy/me/oraclebox/auth/service/model/AccountRepository.groovy: -------------------------------------------------------------------------------- 1 | package me.oraclebox.auth.service.model 2 | 3 | import org.springframework.data.mongodb.repository.MongoRepository 4 | 5 | /** 6 | * 7 | * Created by oraclebox@gmail.com on 17/9/2016. 8 | */ 9 | interface AccountRepository extends MongoRepository { 10 | Account findByUsername(String username); 11 | Account findByEmail(String email); 12 | Account findBySocialId(String socialId); 13 | } 14 | -------------------------------------------------------------------------------- /auth-service/src/main/groovy/me/oraclebox/auth/service/property/ApplicationProperty.groovy: -------------------------------------------------------------------------------- 1 | package me.oraclebox.auth.service.property 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties 4 | import org.springframework.context.annotation.Configuration 5 | 6 | @ConfigurationProperties(prefix = "application") 7 | class ApplicationProperty { 8 | long jwtTTL; 9 | String jwtPhase; 10 | String jwtIssuer; 11 | } 12 | -------------------------------------------------------------------------------- /auth-service/src/main/groovy/me/oraclebox/auth/service/restrofit/FacebookService.groovy: -------------------------------------------------------------------------------- 1 | package me.oraclebox.auth.service.restrofit 2 | 3 | import me.oraclebox.facebook.FacebookAccount 4 | import retrofit2.Call 5 | import retrofit2.http.GET 6 | import retrofit2.http.Query 7 | 8 | /** 9 | * Retrofit service for verify facebook token. 10 | * Created by oraclebox@gmail.com on 14/9/2016. 11 | */ 12 | interface FacebookService { 13 | 14 | String ENDPOINT = "https://graph.facebook.com/v2.7/"; 15 | String ME_QUERY = "about,age_range,birthday,email,id,gender,first_name,middle_name,last_name,name,work,location,locale,languages,religion,timezone,website,updated_time,friends{about,email,gender,id,name,first_name,last_name,middle_name,locale,location},education"; 16 | 17 | @GET("me") 18 | Call me(@Query("fields") String fields, @Query("access_token") String accessToken); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /auth-service/src/main/groovy/me/oraclebox/auth/service/restrofit/ServiceFactory.java: -------------------------------------------------------------------------------- 1 | package me.oraclebox.auth.service.restrofit; 2 | 3 | import retrofit2.Retrofit; 4 | import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; 5 | import retrofit2.converter.gson.GsonConverterFactory; 6 | 7 | public class ServiceFactory { 8 | 9 | /** 10 | * Creates a retrofit service from an arbitrary class (clazz) 11 | * 12 | * @param clazz Java interface of the retrofit service 13 | * @param endPoint REST endpoint url 14 | * @return retrofit service with defined endpoint 15 | */ 16 | public static T createRetrofitService(final Class clazz, final String endPoint) { 17 | final Retrofit restAdapter = new Retrofit.Builder() 18 | .baseUrl(endPoint) 19 | .addConverterFactory(GsonConverterFactory.create()) 20 | .build(); 21 | return restAdapter.create(clazz); 22 | } 23 | 24 | public static T createRetrofitServiceRx(final Class clazz, final String endPoint) { 25 | final Retrofit restAdapter = new Retrofit.Builder() 26 | .baseUrl(endPoint) 27 | .addConverterFactory(GsonConverterFactory.create()) 28 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 29 | .build(); 30 | return restAdapter.create(clazz); 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /auth-service/src/main/groovy/me/oraclebox/auth/service/service/AuthService.groovy: -------------------------------------------------------------------------------- 1 | package me.oraclebox.auth.service.service 2 | 3 | import io.jsonwebtoken.* 4 | import me.oraclebox.auth.service.model.Account 5 | import me.oraclebox.auth.service.model.AccountRepository 6 | import me.oraclebox.auth.service.property.ApplicationProperty 7 | import me.oraclebox.auth.service.restrofit.FacebookService 8 | import me.oraclebox.auth.service.restrofit.ServiceFactory 9 | import me.oraclebox.exception.AuthenticationException 10 | import me.oraclebox.facebook.FacebookAccount 11 | import org.springframework.beans.factory.annotation.Autowired 12 | import org.springframework.data.redis.core.StringRedisTemplate 13 | import org.springframework.security.crypto.password.PasswordEncoder 14 | import org.springframework.stereotype.Service 15 | import retrofit2.Call 16 | import retrofit2.Response 17 | import rx.Observable 18 | 19 | import javax.crypto.spec.SecretKeySpec 20 | import javax.xml.bind.DatatypeConverter 21 | import java.security.Key 22 | 23 | /** 24 | * 25 | * Created by oraclebox on 11/25/2016. 26 | */ 27 | interface AuthService { 28 | Account bySocialId(String socialId); 29 | Account byEmail(String email); 30 | 31 | Account save(Account account); 32 | 33 | boolean validatePassword(String password, Account account); 34 | 35 | String encryptPassword(String password); 36 | 37 | String generateJWT(Account account); 38 | 39 | Account parseJWT(String token); 40 | /** 41 | * Call facebook graph API /me 42 | */ 43 | Observable facebookMe(String accessToken); 44 | } 45 | 46 | @Service 47 | class AuthServiceImpl implements AuthService { 48 | 49 | @Autowired 50 | AccountRepository accountRepository; 51 | @Autowired 52 | PasswordEncoder passwordEncoder; 53 | @Autowired 54 | ApplicationProperty property; 55 | @Autowired 56 | StringRedisTemplate redis; 57 | 58 | @Override 59 | Account bySocialId(String socialId) { 60 | return accountRepository.findBySocialId(socialId); 61 | } 62 | 63 | @Override 64 | Account byEmail(String email) { 65 | return accountRepository.findByEmail(email); 66 | } 67 | 68 | @Override 69 | Account save(Account account) { 70 | return accountRepository.save(account); 71 | } 72 | 73 | @Override 74 | boolean validatePassword(String password, Account account) { 75 | return passwordEncoder.matches(password, account.password); 76 | } 77 | 78 | @Override 79 | String encryptPassword(String password) { 80 | return passwordEncoder.encode(password); 81 | } 82 | 83 | @Override 84 | String generateJWT(Account account) { 85 | //The JWT signature algorithm we will be using to sign the token 86 | SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; 87 | long nowMillis = System.currentTimeMillis(); 88 | Date now = new Date(nowMillis); 89 | 90 | //We will sign our JWT with our ApiKey secret 91 | byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(property.jwtPhase); 92 | Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName()); 93 | 94 | String jwtId = UUID.randomUUID().toString(); 95 | //Let's set the JWT Claims 96 | JwtBuilder builder = Jwts.builder() 97 | .setId(jwtId) 98 | .setIssuedAt(now) 99 | .setSubject(account.id) // User id 100 | .setIssuer(property.jwtIssuer) 101 | .setHeaderParam("typ", "JWT") 102 | .signWith(signatureAlgorithm, signingKey); 103 | 104 | //Let's add the expiration 105 | if (property.jwtTTL >= 0) { 106 | long expMillis = nowMillis + property.jwtTTL; 107 | Date exp = new Date(expMillis); 108 | builder.setExpiration(exp); 109 | } 110 | 111 | String jwt = builder.compact(); 112 | 113 | // Remove previous token record 114 | redis.keys("account:tkn:" + account.id).each { 115 | key -> 116 | String id = redis.opsForValue().get("account:tkn:" + account.id); 117 | if (!id.equals(jwtId)) { 118 | redis.delete("tkn:" + id); 119 | } 120 | } 121 | 122 | // Store to redis 123 | redis.opsForValue().set("tkn:" + jwtId, jwt); 124 | redis.opsForValue().set("account:tkn:" + account.id, jwtId); 125 | redis.expireAt("tkn:" + jwtId, new Date(nowMillis + property.jwtTTL)); 126 | 127 | return jwt; 128 | } 129 | 130 | @Override 131 | Account parseJWT(String token) { 132 | //This line will throw an exception if it is not a signed JWS (as expected) 133 | Jws jwsClaims = Jwts.parser() 134 | .setSigningKey(DatatypeConverter.parseBase64Binary(property.jwtPhase)) 135 | .parseClaimsJws(token); 136 | 137 | if (!jwsClaims.header.getAlgorithm().equals(SignatureAlgorithm.HS256.value)) 138 | throw new AuthenticationException("Invalid JWT token." + jwsClaims.header.getAlgorithm()); 139 | Claims claims = jwsClaims.getBody(); 140 | 141 | // Find record from redis 142 | String record = redis.opsForValue().get("tkn:" + claims.getId()); 143 | if (record == null || !token.equals(record)) { 144 | throw new AuthenticationException("Token is expired."); 145 | } 146 | 147 | Account account = accountRepository.findOne(claims.getSubject()); 148 | if (account == null) 149 | throw new AuthenticationException("Cannot find user account."); 150 | if (!account.active) 151 | throw new AuthenticationException("Account is inactivated."); 152 | return account; 153 | } 154 | 155 | @Override 156 | Observable facebookMe(String accessToken) { 157 | FacebookService service = ServiceFactory.createRetrofitService(FacebookService.class, FacebookService.ENDPOINT); 158 | Call call = service.me(FacebookService.ME_QUERY, accessToken); 159 | Response response = call.execute(); 160 | return Observable.just(response.body()); 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /common/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .idea/ 3 | .gradle/ 4 | -------------------------------------------------------------------------------- /common/build.gradle: -------------------------------------------------------------------------------- 1 | group 'me.oraclebox' 2 | version '1.0-SNAPSHOT' 3 | 4 | apply plugin: 'groovy' 5 | apply plugin: 'java' 6 | 7 | sourceCompatibility = 1.7 8 | 9 | bootRepackage.enabled=false 10 | 11 | repositories { 12 | mavenCentral() 13 | } 14 | 15 | dependencies { 16 | compile 'org.codehaus.groovy:groovy-all:2.3.11' 17 | compile group: 'com.google.code.gson', name: 'gson', version: '2.7' 18 | testCompile group: 'junit', name: 'junit', version: '4.11' 19 | } 20 | -------------------------------------------------------------------------------- /common/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oraclebox/spring-boot-auth-microservice/81ddb3dfc52352af4b45c4a944e74e5a7ef6d0c8/common/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /common/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Nov 25 09:07:27 CST 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.1-all.zip 7 | -------------------------------------------------------------------------------- /common/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 165 | if [[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]]; then 166 | cd "$(dirname "$0")" 167 | fi 168 | 169 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 170 | -------------------------------------------------------------------------------- /common/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /common/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'common' 2 | -------------------------------------------------------------------------------- /common/src/main/groovy/me/oraclebox/exception/AuthenticationException.groovy: -------------------------------------------------------------------------------- 1 | package me.oraclebox.exception 2 | 3 | class AuthenticationException extends Exception { 4 | AuthenticationException() { 5 | } 6 | 7 | AuthenticationException(String var1) { 8 | super(var1) 9 | } 10 | 11 | AuthenticationException(String var1, Throwable var2) { 12 | super(var1, var2) 13 | } 14 | 15 | AuthenticationException(Throwable var1) { 16 | super(var1) 17 | } 18 | 19 | AuthenticationException(String var1, Throwable var2, boolean var3, boolean var4) { 20 | super(var1, var2, var3, var4) 21 | } 22 | } -------------------------------------------------------------------------------- /common/src/main/groovy/me/oraclebox/facebook/AgeRange.java: -------------------------------------------------------------------------------- 1 | 2 | package me.oraclebox.facebook; 3 | 4 | import com.google.gson.annotations.Expose; 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | import javax.annotation.Generated; 8 | 9 | @Generated("org.jsonschema2pojo") 10 | public class AgeRange { 11 | 12 | @SerializedName("min") 13 | @Expose 14 | public Integer min; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /common/src/main/groovy/me/oraclebox/facebook/Concentration.java: -------------------------------------------------------------------------------- 1 | 2 | package me.oraclebox.facebook; 3 | 4 | import com.google.gson.annotations.Expose; 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | import javax.annotation.Generated; 8 | 9 | @Generated("org.jsonschema2pojo") 10 | public class Concentration { 11 | 12 | @SerializedName("id") 13 | //@Expose 14 | public String id; 15 | @SerializedName("name") 16 | @Expose 17 | public String name; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /common/src/main/groovy/me/oraclebox/facebook/Degree.java: -------------------------------------------------------------------------------- 1 | 2 | package me.oraclebox.facebook; 3 | 4 | import com.google.gson.annotations.Expose; 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | import javax.annotation.Generated; 8 | 9 | @Generated("org.jsonschema2pojo") 10 | public class Degree { 11 | 12 | @SerializedName("id") 13 | //@Expose 14 | public String id; 15 | @SerializedName("name") 16 | @Expose 17 | public String name; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /common/src/main/groovy/me/oraclebox/facebook/Education.java: -------------------------------------------------------------------------------- 1 | 2 | package me.oraclebox.facebook; 3 | 4 | import com.google.gson.annotations.Expose; 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | import javax.annotation.Generated; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | @Generated("org.jsonschema2pojo") 12 | public class Education { 13 | 14 | @SerializedName("school") 15 | @Expose 16 | public School school; 17 | @SerializedName("type") 18 | @Expose 19 | public String type; 20 | @SerializedName("year") 21 | @Expose 22 | public Year year; 23 | @SerializedName("id") 24 | //@Expose 25 | public String id; 26 | @SerializedName("concentration") 27 | @Expose 28 | public List concentration = new ArrayList(); 29 | @SerializedName("degree") 30 | @Expose 31 | public Degree degree; 32 | 33 | } 34 | -------------------------------------------------------------------------------- /common/src/main/groovy/me/oraclebox/facebook/Employer.java: -------------------------------------------------------------------------------- 1 | 2 | package me.oraclebox.facebook; 3 | 4 | import com.google.gson.annotations.Expose; 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | import javax.annotation.Generated; 8 | 9 | @Generated("org.jsonschema2pojo") 10 | public class Employer { 11 | 12 | @SerializedName("id") 13 | //@Expose 14 | public String id; 15 | @SerializedName("name") 16 | @Expose 17 | public String name; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /common/src/main/groovy/me/oraclebox/facebook/FacebookAccount.java: -------------------------------------------------------------------------------- 1 | 2 | package me.oraclebox.facebook; 3 | 4 | import com.google.gson.annotations.Expose; 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | import javax.annotation.Generated; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | @Generated("org.jsonschema2pojo") 12 | public class FacebookAccount { 13 | 14 | @SerializedName("about") 15 | @Expose 16 | public String about; 17 | @SerializedName("age_range") 18 | @Expose 19 | public AgeRange ageRange; 20 | @SerializedName("birthday") 21 | @Expose 22 | public String birthday; 23 | @SerializedName("email") 24 | @Expose 25 | public String email; 26 | @SerializedName("id") 27 | @Expose 28 | public String id; 29 | @SerializedName("gender") 30 | @Expose 31 | public String gender; 32 | @SerializedName("first_name") 33 | @Expose 34 | public String firstName; 35 | @SerializedName("last_name") 36 | @Expose 37 | public String lastName; 38 | @SerializedName("name") 39 | @Expose 40 | public String name; 41 | // @SerializedName("work") 42 | // @Expose 43 | // public List work = new ArrayList(); 44 | @SerializedName("location") 45 | @Expose 46 | public Location location; 47 | @SerializedName("locale") 48 | @Expose 49 | public String locale; 50 | @SerializedName("languages") 51 | @Expose 52 | public List languages = new ArrayList(); 53 | @SerializedName("timezone") 54 | @Expose 55 | public Integer timezone; 56 | @SerializedName("updated_time") 57 | @Expose 58 | public String updatedTime; 59 | @SerializedName("friends") 60 | @Expose 61 | public Friends friends; 62 | // @SerializedName("education") 63 | // @Expose 64 | // public List education = new ArrayList(); 65 | 66 | } 67 | -------------------------------------------------------------------------------- /common/src/main/groovy/me/oraclebox/facebook/Friends.java: -------------------------------------------------------------------------------- 1 | 2 | package me.oraclebox.facebook; 3 | 4 | import com.google.gson.annotations.Expose; 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | import javax.annotation.Generated; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | @Generated("org.jsonschema2pojo") 12 | public class Friends { 13 | 14 | @SerializedName("data") 15 | @Expose 16 | public List data = new ArrayList(); 17 | @SerializedName("summary") 18 | @Expose 19 | public Summary summary; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /common/src/main/groovy/me/oraclebox/facebook/Language.java: -------------------------------------------------------------------------------- 1 | 2 | package me.oraclebox.facebook; 3 | 4 | import com.google.gson.annotations.Expose; 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | import javax.annotation.Generated; 8 | 9 | @Generated("org.jsonschema2pojo") 10 | public class Language { 11 | 12 | @SerializedName("id") 13 | //@Expose 14 | public String id; 15 | @SerializedName("name") 16 | @Expose 17 | public String name; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /common/src/main/groovy/me/oraclebox/facebook/Location.java: -------------------------------------------------------------------------------- 1 | 2 | package me.oraclebox.facebook; 3 | 4 | import com.google.gson.annotations.Expose; 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | import javax.annotation.Generated; 8 | 9 | @Generated("org.jsonschema2pojo") 10 | public class Location { 11 | 12 | @SerializedName("id") 13 | //@Expose 14 | public String id; 15 | @SerializedName("name") 16 | @Expose 17 | public String name; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /common/src/main/groovy/me/oraclebox/facebook/School.java: -------------------------------------------------------------------------------- 1 | 2 | package me.oraclebox.facebook; 3 | 4 | import com.google.gson.annotations.Expose; 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | import javax.annotation.Generated; 8 | 9 | @Generated("org.jsonschema2pojo") 10 | public class School { 11 | 12 | @SerializedName("id") 13 | //@Expose 14 | public String id; 15 | @SerializedName("name") 16 | @Expose 17 | public String name; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /common/src/main/groovy/me/oraclebox/facebook/Summary.java: -------------------------------------------------------------------------------- 1 | 2 | package me.oraclebox.facebook; 3 | 4 | import com.google.gson.annotations.Expose; 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | import javax.annotation.Generated; 8 | 9 | @Generated("org.jsonschema2pojo") 10 | public class Summary { 11 | 12 | @SerializedName("total_count") 13 | @Expose 14 | public Integer totalCount; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /common/src/main/groovy/me/oraclebox/facebook/Work.java: -------------------------------------------------------------------------------- 1 | 2 | package me.oraclebox.facebook; 3 | 4 | import com.google.gson.annotations.Expose; 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | import javax.annotation.Generated; 8 | 9 | @Generated("org.jsonschema2pojo") 10 | public class Work { 11 | 12 | @SerializedName("end_date") 13 | @Expose 14 | public String endDate; 15 | @SerializedName("employer") 16 | @Expose 17 | public Employer employer; 18 | @SerializedName("start_date") 19 | @Expose 20 | public String startDate; 21 | @SerializedName("id") 22 | //@Expose 23 | public String id; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /common/src/main/groovy/me/oraclebox/facebook/Year.java: -------------------------------------------------------------------------------- 1 | 2 | package me.oraclebox.facebook; 3 | 4 | import com.google.gson.annotations.Expose; 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | import javax.annotation.Generated; 8 | 9 | @Generated("org.jsonschema2pojo") 10 | public class Year { 11 | 12 | @SerializedName("id") 13 | //@Expose 14 | public String id; 15 | @SerializedName("name") 16 | @Expose 17 | public String name; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /common/src/main/groovy/me/oraclebox/facebook/friends/taggable/Cursors.java: -------------------------------------------------------------------------------- 1 | 2 | package me.oraclebox.facebook.friends.taggable; 3 | 4 | import com.google.gson.annotations.Expose; 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | import javax.annotation.Generated; 8 | 9 | @Generated("org.jsonschema2pojo") 10 | public class Cursors { 11 | 12 | @SerializedName("before") 13 | @Expose 14 | public String before; 15 | @SerializedName("after") 16 | @Expose 17 | public String after; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /common/src/main/groovy/me/oraclebox/facebook/friends/taggable/Data.java: -------------------------------------------------------------------------------- 1 | 2 | package me.oraclebox.facebook.friends.taggable; 3 | 4 | import com.google.gson.annotations.Expose; 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | import javax.annotation.Generated; 8 | 9 | @Generated("org.jsonschema2pojo") 10 | public class Data { 11 | 12 | @SerializedName("is_silhouette") 13 | @Expose 14 | public Boolean isSilhouette; 15 | @SerializedName("url") 16 | @Expose 17 | public String url; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /common/src/main/groovy/me/oraclebox/facebook/friends/taggable/Datum.java: -------------------------------------------------------------------------------- 1 | 2 | package me.oraclebox.facebook.friends.taggable; 3 | 4 | import com.google.gson.annotations.Expose; 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | import javax.annotation.Generated; 8 | 9 | @Generated("org.jsonschema2pojo") 10 | public class Datum { 11 | 12 | @SerializedName("id") 13 | @Expose 14 | public String id; 15 | @SerializedName("name") 16 | @Expose 17 | public String name; 18 | @SerializedName("picture") 19 | @Expose 20 | public Picture picture; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /common/src/main/groovy/me/oraclebox/facebook/friends/taggable/Paging.java: -------------------------------------------------------------------------------- 1 | 2 | package me.oraclebox.facebook.friends.taggable; 3 | 4 | import com.google.gson.annotations.Expose; 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | import javax.annotation.Generated; 8 | 9 | @Generated("org.jsonschema2pojo") 10 | public class Paging { 11 | 12 | @SerializedName("cursors") 13 | @Expose 14 | public Cursors cursors; 15 | @SerializedName("next") 16 | @Expose 17 | public String next; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /common/src/main/groovy/me/oraclebox/facebook/friends/taggable/Picture.java: -------------------------------------------------------------------------------- 1 | 2 | package me.oraclebox.facebook.friends.taggable; 3 | 4 | import com.google.gson.annotations.Expose; 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | import javax.annotation.Generated; 8 | 9 | @Generated("org.jsonschema2pojo") 10 | public class Picture { 11 | 12 | @SerializedName("data") 13 | @Expose 14 | public Data data; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /common/src/main/groovy/me/oraclebox/facebook/friends/taggable/TaggableFriends.java: -------------------------------------------------------------------------------- 1 | 2 | package me.oraclebox.facebook.friends.taggable; 3 | 4 | import com.google.gson.annotations.Expose; 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | import javax.annotation.Generated; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | @Generated("org.jsonschema2pojo") 12 | public class TaggableFriends { 13 | 14 | @SerializedName("data") 15 | @Expose 16 | public List data = new ArrayList(); 17 | @SerializedName("paging") 18 | @Expose 19 | public Paging paging; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /common/src/main/groovy/me/oraclebox/http/ResultModel.groovy: -------------------------------------------------------------------------------- 1 | package me.oraclebox.http 2 | 3 | /** 4 | * Response model for all services http response. 5 | * 所有Http服務的返回格式 6 | * Created by oraclebox on 14/9/2016. 7 | */ 8 | class ResultModel { 9 | int code; 10 | String message; 11 | String token; 12 | T data; 13 | 14 | public ResultModel() {} 15 | 16 | public ResultModel(ResultStatus status, String message, T data) { 17 | this.code = status.getCode(); 18 | this.message = message != null ? message : status.getMessage(); 19 | this.data = data; 20 | } 21 | 22 | public ResultModel(ResultStatus status, String message, T data, String token) { 23 | this.code = status.getCode(); 24 | this.message = message != null ? message : status.getMessage(); 25 | this.data = data; 26 | this.token = token; 27 | } 28 | 29 | 30 | public static ResultModel _200(String message, T data) { 31 | return new ResultModel(ResultStatus.SUCCESS, message, data); 32 | } 33 | 34 | public static ResultModel _200(String message, String token, T data) { 35 | return new ResultModel(ResultStatus.SUCCESS, message, data, token); 36 | } 37 | 38 | public static ResultModel _403(String message, T data) { 39 | return new ResultModel(ResultStatus.FORBIDDEN, message, data); 40 | } 41 | 42 | public static ResultModel _404(String message, T data) { 43 | return new ResultModel(ResultStatus.NOT_FOUND, message, data); 44 | } 45 | 46 | public static ResultModel _400(String message, T data) { 47 | return new ResultModel(ResultStatus.BAD_REQUEST, message, data); 48 | } 49 | 50 | public static ResultModel _500(String message, T data) { 51 | return new ResultModel(ResultStatus.INTERNAL_SERVER_ERROR, message, data); 52 | } 53 | 54 | public static ResultModel unauthorized(String message, T data) { 55 | return new ResultModel(ResultStatus.UNAUTHORIZED, message, data); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /common/src/main/groovy/me/oraclebox/http/ResultStatus.groovy: -------------------------------------------------------------------------------- 1 | package me.oraclebox.http 2 | 3 | /** 4 | * 自定義請求狀態碼 5 | */ 6 | public enum ResultStatus { 7 | SUCCESS(200, "success"), 8 | CREATED(201, "created"), 9 | BAD_REQUEST(400, "bad request"), 10 | UNAUTHORIZED(401, "unauthorized"), 11 | FORBIDDEN(403, "forbidden"), 12 | NOT_FOUND(404, "not found"), 13 | INTERNAL_SERVER_ERROR(500, "Internal server error") 14 | 15 | private int code; 16 | private String message; 17 | 18 | ResultStatus(int code, String message) { 19 | this.code = code; 20 | this.message = message; 21 | } 22 | 23 | public int getCode() { 24 | return code; 25 | } 26 | 27 | public void setCode(int code) { 28 | this.code = code; 29 | } 30 | 31 | public String getMessage() { 32 | return message; 33 | } 34 | 35 | public void setMessage(String message) { 36 | this.message = message; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /docs/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oraclebox/spring-boot-auth-microservice/81ddb3dfc52352af4b45c4a944e74e5a7ef6d0c8/docs/overview.png -------------------------------------------------------------------------------- /docs/spring-boot-auth-microservice-auth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oraclebox/spring-boot-auth-microservice/81ddb3dfc52352af4b45c4a944e74e5a7ef6d0c8/docs/spring-boot-auth-microservice-auth.png -------------------------------------------------------------------------------- /docs/temp.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /eureka-server/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .idea/ 3 | .gradle/ 4 | 5 | -------------------------------------------------------------------------------- /eureka-server/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: ${PORT:8761} 3 | eureka: 4 | instance: 5 | preferIpAddress: true 6 | client: 7 | registerWithEureka: false 8 | server: 9 | # When eureka first starts up without peers it takes about 5 mins for it to start serving requests 10 | # because it waits for all clients to register completely before it can give out the list. Disable it by set to 0 11 | waitTimeInMsWhenSyncEmpty: 0 12 | enableSelfPreservation: false 13 | evictionIntervalTimerInMs: 6000 14 | logging: 15 | level: 16 | com: 17 | netflix: 18 | eureka: OFF 19 | discovery: OFF -------------------------------------------------------------------------------- /eureka-server/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | springBootVersion = '1.4.3.BUILD-SNAPSHOT' 4 | } 5 | repositories { 6 | mavenCentral() 7 | maven { url "https://repo.spring.io/snapshot" } 8 | maven { url "https://repo.spring.io/milestone" } 9 | } 10 | dependencies { 11 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 12 | classpath "io.spring.gradle:dependency-management-plugin:0.5.6.RELEASE" 13 | } 14 | } 15 | 16 | allprojects { 17 | apply plugin: 'idea' 18 | apply plugin: 'groovy' 19 | apply plugin: 'java' 20 | apply plugin: 'org.springframework.boot' 21 | sourceCompatibility = 1.8 22 | targetCompatibility = 1.8 23 | } 24 | 25 | 26 | jar { 27 | baseName = 'eureka-server' 28 | version = '0.0.1-SNAPSHOT' 29 | } 30 | 31 | repositories { 32 | mavenCentral() 33 | maven { url "https://repo.spring.io/snapshot" } 34 | maven { url "https://repo.spring.io/milestone" } 35 | } 36 | 37 | dependencyManagement { 38 | imports { 39 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:Camden.BUILD-SNAPSHOT" 40 | } 41 | } 42 | 43 | dependencies { 44 | compile('org.codehaus.groovy:groovy-all:2.3.11') 45 | compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-eureka-server', version: '1.2.3.RELEASE' 46 | testCompile('org.springframework.boot:spring-boot-starter-test') 47 | } 48 | 49 | -------------------------------------------------------------------------------- /eureka-server/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oraclebox/spring-boot-auth-microservice/81ddb3dfc52352af4b45c4a944e74e5a7ef6d0c8/eureka-server/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /eureka-server/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Nov 28 09:27:03 CST 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.1-all.zip 7 | -------------------------------------------------------------------------------- /eureka-server/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 165 | if [[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]]; then 166 | cd "$(dirname "$0")" 167 | fi 168 | 169 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 170 | -------------------------------------------------------------------------------- /eureka-server/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /eureka-server/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'eureka-server' 2 | 3 | -------------------------------------------------------------------------------- /eureka-server/src/main/groovy/me/oraclebox/EurekaApplication.groovy: -------------------------------------------------------------------------------- 1 | package me.oraclebox 2 | 3 | import org.springframework.boot.SpringApplication 4 | import org.springframework.boot.autoconfigure.SpringBootApplication 5 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient 6 | import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer 7 | 8 | @EnableDiscoveryClient 9 | @EnableEurekaServer 10 | @SpringBootApplication 11 | class EurekaApplication { 12 | public static void main(String[] args) { 13 | SpringApplication.run(EurekaApplication.class, args); 14 | } 15 | } 16 | --------------------------------------------------------------------------------