From 1ed36a41f207e543a39159f3f547d415ae81e41d Mon Sep 17 00:00:00 2001 From: "yadong.zhang" Date: Tue, 2 Mar 2021 21:45:26 +0800 Subject: [PATCH] :bookmark: pre-releasing 1.0.1-alpha --- jap-core/pom.xml | 2 +- .../java/com/fujieid/jap/core/JapConfig.java | 126 --------- .../java/com/fujieid/jap/core/JapConst.java | 2 + .../java/com/fujieid/jap/core/JapUser.java | 11 + .../com/fujieid/jap/core/JapUserService.java | 14 +- .../com/fujieid/jap/core/cache/JapCache.java | 7 + .../jap/core/cache/JapCacheConfig.java | 2 +- .../fujieid/jap/core/cache/JapLocalCache.java | 10 + .../core/{ => config}/AuthenticateConfig.java | 2 +- .../fujieid/jap/core/config/JapConfig.java | 86 ++++++ .../jap/core/context/JapAuthentication.java | 123 +++++++-- .../fujieid/jap/core/context/JapContext.java | 2 +- .../jap/core/exception/JapException.java | 35 ++- .../core/exception/JapOauth2Exception.java | 9 - .../core/exception/JapSocialException.java | 8 - .../jap/core/exception/OidcException.java | 8 - .../fujieid/jap/core/result/JapErrorCode.java | 57 ++++ .../fujieid/jap/core/result/JapResponse.java | 86 ++++++ .../jap/core/store/SessionJapUserStore.java | 23 ++ .../jap/core/store/SsoJapUserStore.java | 11 +- .../core/strategy/AbstractJapStrategy.java | 28 +- .../jap/core/strategy/JapStrategy.java | 9 +- .../fujieid/jap/core/util/JapTokenHelper.java | 64 +++++ .../fujieid/jap/core/{ => util}/JapUtil.java | 11 +- .../jap/core/cache/JapLocalCacheTest.java | 3 +- .../core/context/JapAuthenticationTest.java | 254 ++++++++++++++++++ .../fujieid/jap/core/util/JapUtilTest.java | 47 ++++ 27 files changed, 833 insertions(+), 207 deletions(-) delete mode 100644 jap-core/src/main/java/com/fujieid/jap/core/JapConfig.java rename jap-core/src/main/java/com/fujieid/jap/core/{ => config}/AuthenticateConfig.java (96%) create mode 100644 jap-core/src/main/java/com/fujieid/jap/core/config/JapConfig.java create mode 100644 jap-core/src/main/java/com/fujieid/jap/core/result/JapErrorCode.java create mode 100644 jap-core/src/main/java/com/fujieid/jap/core/result/JapResponse.java create mode 100644 jap-core/src/main/java/com/fujieid/jap/core/util/JapTokenHelper.java rename jap-core/src/main/java/com/fujieid/jap/core/{ => util}/JapUtil.java (80%) create mode 100644 jap-core/src/test/java/com/fujieid/jap/core/context/JapAuthenticationTest.java create mode 100644 jap-core/src/test/java/com/fujieid/jap/core/util/JapUtilTest.java diff --git a/jap-core/pom.xml b/jap-core/pom.xml index 31c6a92..2383664 100644 --- a/jap-core/pom.xml +++ b/jap-core/pom.xml @@ -5,7 +5,7 @@ com.fujieid jap - 1.0.1 + 1.0.1-alpha 4.0.0 diff --git a/jap-core/src/main/java/com/fujieid/jap/core/JapConfig.java b/jap-core/src/main/java/com/fujieid/jap/core/JapConfig.java deleted file mode 100644 index 5c594c9..0000000 --- a/jap-core/src/main/java/com/fujieid/jap/core/JapConfig.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com). - *

- * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.gnu.org/licenses/lgpl.html - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.fujieid.jap.core; - -import com.fujieid.jap.sso.config.JapSsoConfig; - -/** - * Jap configuration. - * - * @author yadong.zhang (yadong.zhang0415(a)gmail.com) - * @version 1.0.0 - * @since 1.0.0 - */ -public class JapConfig { - - /** - * Login Url. Default is `/login` - */ - private String loginUrl = "/login"; - - /** - * Logout Url. Default is `/logout` - */ - private String logoutUrl = "/logout"; - - /** - * Enable sso, is not enabled by default - */ - private boolean sso; - - /** - * SSO config - */ - private JapSsoConfig ssoConfig; - - /** - * After successful login, redirect to {@code successRedirect}. Default is `/` - */ - private String successRedirect = "/"; - - /** - * After logout, redirect to {@code logoutRedirect}. Default is `/` - */ - private String logoutRedirect = "/"; - - /** - * After failed login, redirect to {@code failureRedirect}. Default is `/error` - */ - private String failureRedirect = "/error"; - - public String getLoginUrl() { - return loginUrl; - } - - public JapConfig setLoginUrl(String loginUrl) { - this.loginUrl = loginUrl; - return this; - } - - public String getLogoutUrl() { - return logoutUrl; - } - - public JapConfig setLogoutUrl(String logoutUrl) { - this.logoutUrl = logoutUrl; - return this; - } - - public boolean isSso() { - return sso; - } - - public JapConfig setSso(boolean sso) { - this.sso = sso; - return this; - } - - public JapSsoConfig getSsoConfig() { - return ssoConfig; - } - - public JapConfig setSsoConfig(JapSsoConfig ssoConfig) { - this.ssoConfig = ssoConfig; - return this; - } - - public String getSuccessRedirect() { - return successRedirect; - } - - public JapConfig setSuccessRedirect(String successRedirect) { - this.successRedirect = successRedirect; - return this; - } - - public String getFailureRedirect() { - return failureRedirect; - } - - public JapConfig setFailureRedirect(String failureRedirect) { - this.failureRedirect = failureRedirect; - return this; - } - - public String getLogoutRedirect() { - return logoutRedirect; - } - - public JapConfig setLogoutRedirect(String logoutRedirect) { - this.logoutRedirect = logoutRedirect; - return this; - } -} diff --git a/jap-core/src/main/java/com/fujieid/jap/core/JapConst.java b/jap-core/src/main/java/com/fujieid/jap/core/JapConst.java index e22acd2..c2ef07d 100644 --- a/jap-core/src/main/java/com/fujieid/jap/core/JapConst.java +++ b/jap-core/src/main/java/com/fujieid/jap/core/JapConst.java @@ -28,6 +28,8 @@ public interface JapConst { String SESSION_USER_KEY = "_jap:session:user"; + String USER_TOKEN_KEY = "_jap:user:token:"; + /** * default delimiter */ diff --git a/jap-core/src/main/java/com/fujieid/jap/core/JapUser.java b/jap-core/src/main/java/com/fujieid/jap/core/JapUser.java index b38b8ab..4013d10 100644 --- a/jap-core/src/main/java/com/fujieid/jap/core/JapUser.java +++ b/jap-core/src/main/java/com/fujieid/jap/core/JapUser.java @@ -49,6 +49,8 @@ public class JapUser implements Serializable { */ private Object additional; + private String token; + public String getUserId() { return userId; } @@ -84,4 +86,13 @@ public class JapUser implements Serializable { this.additional = additional; return this; } + + public String getToken() { + return token; + } + + public JapUser setToken(String token) { + this.token = token; + return this; + } } diff --git a/jap-core/src/main/java/com/fujieid/jap/core/JapUserService.java b/jap-core/src/main/java/com/fujieid/jap/core/JapUserService.java index be0b6ba..083eeca 100644 --- a/jap-core/src/main/java/com/fujieid/jap/core/JapUserService.java +++ b/jap-core/src/main/java/com/fujieid/jap/core/JapUserService.java @@ -15,8 +15,6 @@ */ package com.fujieid.jap.core; -import com.fujieid.jap.core.exception.JapUserException; - import java.util.Map; /** @@ -35,7 +33,7 @@ public interface JapUserService { * @return JapUser */ default JapUser getById(String userId) { - throw new JapUserException("JapUserService#getById(String) must be overridden by subclass"); + return null; } /** @@ -47,7 +45,7 @@ public interface JapUserService { * @return JapUser */ default JapUser getByName(String username) { - throw new JapUserException("JapUserService#getByName(String) must be overridden by subclass"); + return null; } /** @@ -60,7 +58,7 @@ public interface JapUserService { * @return {@code boolean} When true is returned, the password matches, otherwise the password is wrong */ default boolean validPassword(String password, JapUser user) { - throw new JapUserException("JapUserService#validPassword(String, JapUser) must be overridden by subclass"); + return false; } /** @@ -73,7 +71,7 @@ public interface JapUserService { * @return JapUser */ default JapUser getByPlatformAndUid(String platform, String uid) { - throw new JapUserException("JapUserService#getByPlatformAndUid(String, String) must be overridden by subclass"); + return null; } /** @@ -85,7 +83,7 @@ public interface JapUserService { * @return When saving successfully, return {@code JapUser}, otherwise return {@code null} */ default JapUser createAndGetSocialUser(Object userInfo) { - throw new JapUserException("JapUserService#createSocialUser(AuthUser) must be overridden by subclass"); + return null; } /** @@ -100,7 +98,7 @@ public interface JapUserService { * @return When saving successfully, return {@code JapUser}, otherwise return {@code null} */ default JapUser createAndGetOauth2User(String platform, Map userInfo, Object tokenInfo) { - throw new JapUserException("JapUserService#createAndGetOauth2User(String, Map, Object) must be overridden by subclass"); + return null; } } diff --git a/jap-core/src/main/java/com/fujieid/jap/core/cache/JapCache.java b/jap-core/src/main/java/com/fujieid/jap/core/cache/JapCache.java index 4523224..f3dd67a 100644 --- a/jap-core/src/main/java/com/fujieid/jap/core/cache/JapCache.java +++ b/jap-core/src/main/java/com/fujieid/jap/core/cache/JapCache.java @@ -58,4 +58,11 @@ public interface JapCache { * @return boolean */ boolean containsKey(String key); + + /** + * Delete the key from the cache + * + * @param key Cache key + */ + void removeKey(String key); } diff --git a/jap-core/src/main/java/com/fujieid/jap/core/cache/JapCacheConfig.java b/jap-core/src/main/java/com/fujieid/jap/core/cache/JapCacheConfig.java index 9771ae8..fa5eb3e 100644 --- a/jap-core/src/main/java/com/fujieid/jap/core/cache/JapCacheConfig.java +++ b/jap-core/src/main/java/com/fujieid/jap/core/cache/JapCacheConfig.java @@ -29,5 +29,5 @@ public class JapCacheConfig { /** * The cache expiration time is 1 day by default */ - public static long timeout = TimeUnit.DAYS.toMillis(1); + public static long timeout = TimeUnit.DAYS.toMillis(7); } diff --git a/jap-core/src/main/java/com/fujieid/jap/core/cache/JapLocalCache.java b/jap-core/src/main/java/com/fujieid/jap/core/cache/JapLocalCache.java index 75a45cb..ba1a2f7 100644 --- a/jap-core/src/main/java/com/fujieid/jap/core/cache/JapLocalCache.java +++ b/jap-core/src/main/java/com/fujieid/jap/core/cache/JapLocalCache.java @@ -79,4 +79,14 @@ public class JapLocalCache implements JapCache { public boolean containsKey(String key) { return LOCAL_CACHE.containsKey(key); } + + /** + * Delete the key from the cache + * + * @param key Cache key + */ + @Override + public void removeKey(String key) { + LOCAL_CACHE.remove(key); + } } diff --git a/jap-core/src/main/java/com/fujieid/jap/core/AuthenticateConfig.java b/jap-core/src/main/java/com/fujieid/jap/core/config/AuthenticateConfig.java similarity index 96% rename from jap-core/src/main/java/com/fujieid/jap/core/AuthenticateConfig.java rename to jap-core/src/main/java/com/fujieid/jap/core/config/AuthenticateConfig.java index 521e376..193d1a0 100644 --- a/jap-core/src/main/java/com/fujieid/jap/core/AuthenticateConfig.java +++ b/jap-core/src/main/java/com/fujieid/jap/core/config/AuthenticateConfig.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.fujieid.jap.core; +package com.fujieid.jap.core.config; /** * Authenticate configuration. The config parameter for each policy authenticate must be inherited from this class. diff --git a/jap-core/src/main/java/com/fujieid/jap/core/config/JapConfig.java b/jap-core/src/main/java/com/fujieid/jap/core/config/JapConfig.java new file mode 100644 index 0000000..8cd9c2b --- /dev/null +++ b/jap-core/src/main/java/com/fujieid/jap/core/config/JapConfig.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com). + *

+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.fujieid.jap.core.config; + +import com.fujieid.jap.sso.config.JapSsoConfig; + +import java.util.concurrent.TimeUnit; + +/** + * Jap configuration. + * + * @author yadong.zhang (yadong.zhang0415(a)gmail.com) + * @version 1.0.0 + * @since 1.0.0 + */ +public class JapConfig { + + /** + * Enable sso, is not enabled by default + */ + private boolean sso; + + /** + * SSO config + */ + private JapSsoConfig ssoConfig; + + /** + * After the user logs in successfully, the valid time of the token, in milliseconds, the default validity period is 7 days + */ + private long tokenExpireTime = TimeUnit.DAYS.toMillis(7); + + /** + * The expiration time of the jap cache, in milliseconds, the default validity period is 7 days + */ + private long cacheExpireTime = TimeUnit.DAYS.toMillis(7); + + public boolean isSso() { + return sso; + } + + public JapConfig setSso(boolean sso) { + this.sso = sso; + return this; + } + + public JapSsoConfig getSsoConfig() { + return ssoConfig; + } + + public JapConfig setSsoConfig(JapSsoConfig ssoConfig) { + this.ssoConfig = ssoConfig; + return this; + } + + public long getTokenExpireTime() { + return tokenExpireTime; + } + + public JapConfig setTokenExpireTime(long tokenExpireTime) { + this.tokenExpireTime = tokenExpireTime; + return this; + } + + public long getCacheExpireTime() { + return cacheExpireTime; + } + + public JapConfig setCacheExpireTime(long cacheExpireTime) { + this.cacheExpireTime = cacheExpireTime; + return this; + } +} diff --git a/jap-core/src/main/java/com/fujieid/jap/core/context/JapAuthentication.java b/jap-core/src/main/java/com/fujieid/jap/core/context/JapAuthentication.java index 9120ffd..1d4c1b6 100644 --- a/jap-core/src/main/java/com/fujieid/jap/core/context/JapAuthentication.java +++ b/jap-core/src/main/java/com/fujieid/jap/core/context/JapAuthentication.java @@ -16,18 +16,24 @@ package com.fujieid.jap.core.context; import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.extra.servlet.ServletUtil; -import com.fujieid.jap.core.JapConfig; import com.fujieid.jap.core.JapUser; -import com.fujieid.jap.core.JapUtil; +import com.fujieid.jap.core.cache.JapCache; +import com.fujieid.jap.core.config.JapConfig; +import com.fujieid.jap.core.result.JapErrorCode; +import com.fujieid.jap.core.result.JapResponse; import com.fujieid.jap.core.store.JapUserStore; +import com.fujieid.jap.core.util.JapTokenHelper; +import com.xkcoding.json.util.Kv; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.Serializable; +import java.util.Date; import java.util.Map; -import java.util.Optional; /** * Manage the context of jap, after successful login, @@ -43,14 +49,31 @@ public class JapAuthentication implements Serializable { private JapAuthentication() { } + /** + * Get JAP Context + * + * @return JapContext + */ public static JapContext getContext() { return context; } + /** + * Save JAP Context + * + * @param japContext JAP Context details + */ public static void setContext(JapContext japContext) { context = japContext; } + /** + * Get the currently logged in user + * + * @param request Current request + * @param response Current response + * @return JapUser + */ public static JapUser getUser(HttpServletRequest request, HttpServletResponse response) { if (null == context) { return null; @@ -62,28 +85,94 @@ public class JapAuthentication implements Serializable { return japUserStore.get(request, response); } - public static void logout(HttpServletRequest request, HttpServletResponse response) { + /** + * Check whether the user is logged in. Reference method of use: + *

+ *

+ * + * if(!JapAuthentication.checkUser(request, response).isSuccess()) {
+ * // Not logged in.
+ * }
+ *
+ *

+ *

+ * Is equivalent to the following code: + *

+ *

+ * + * JapUser japUser = JapAuthentication.getUser(request, response);
+ * if (null == japUser) {
+ * // Not logged in.
+ * }
+ *
+ * + * @param request Current request + * @param response Current response + * @return JapResponse + */ + public static JapResponse checkUser(HttpServletRequest request, HttpServletResponse response) { + JapUser japUser = getUser(request, response); + if (null == japUser) { + return JapResponse.error(JapErrorCode.NOT_LOGGED_IN); + } + return JapResponse.success(japUser); + } + + /** + * Verify the legitimacy of JAP Token + * + * @param token jwt token + * @return Map + */ + public static Map checkToken(String token) { + if (null == context || ObjectUtil.isEmpty(token)) { + return null; + } + JapCache japCache = context.getCache(); + if (null == japCache) { + return null; + } + Map tokenMap = new JapTokenHelper(japCache).checkToken(token); + if (MapUtil.isNotEmpty(tokenMap)) { + Kv kv = new Kv(); + kv.putAll(tokenMap); + // Get the token creation time, multiplied by 1000 is the number of milliseconds + long iat = kv.getLong("iat") * 1000; + JapConfig japConfig = context.getConfig(); + // Get token expiration time + long tokenExpireTime = japConfig.getTokenExpireTime(); + // The token is available when the token creation time plus the token expiration time is later than the current time, + // otherwise the token has expired + if (new Date(iat + tokenExpireTime).after(new Date())) { + return tokenMap; + } + } + return null; + } + + /** + * sign out + * + * @param request Current request + * @param response Current response + * @return boolean + */ + public static boolean logout(HttpServletRequest request, HttpServletResponse response) { JapUserStore japUserStore = context.getUserStore(); if (null == japUserStore) { - return; + return false; } japUserStore.remove(request, response); // Clear all cookie information Map cookieMap = ServletUtil.readCookieMap(request); - if (CollectionUtil.isEmpty(cookieMap)) { - return; - } - cookieMap.forEach((key, cookie) -> { - cookie.setMaxAge(0); - response.addCookie(cookie); - }); - - JapConfig config = context.getConfig(); - if (null != config) { - String logoutRedirect = config.getLogoutRedirect(); - JapUtil.redirect(Optional.ofNullable(logoutRedirect).orElse(config.getLoginUrl()), response); + if (CollectionUtil.isNotEmpty(cookieMap)) { + cookieMap.forEach((key, cookie) -> { + cookie.setMaxAge(0); + response.addCookie(cookie); + }); } + return true; } } diff --git a/jap-core/src/main/java/com/fujieid/jap/core/context/JapContext.java b/jap-core/src/main/java/com/fujieid/jap/core/context/JapContext.java index 5b14b2d..c8a5110 100644 --- a/jap-core/src/main/java/com/fujieid/jap/core/context/JapContext.java +++ b/jap-core/src/main/java/com/fujieid/jap/core/context/JapContext.java @@ -15,7 +15,7 @@ */ package com.fujieid.jap.core.context; -import com.fujieid.jap.core.JapConfig; +import com.fujieid.jap.core.config.JapConfig; import com.fujieid.jap.core.cache.JapCache; import com.fujieid.jap.core.store.JapUserStore; diff --git a/jap-core/src/main/java/com/fujieid/jap/core/exception/JapException.java b/jap-core/src/main/java/com/fujieid/jap/core/exception/JapException.java index e0fb157..c50186f 100644 --- a/jap-core/src/main/java/com/fujieid/jap/core/exception/JapException.java +++ b/jap-core/src/main/java/com/fujieid/jap/core/exception/JapException.java @@ -15,6 +15,8 @@ */ package com.fujieid.jap.core.exception; +import com.fujieid.jap.core.result.JapErrorCode; + /** * Wrap all exception information related to the JAP * @@ -23,13 +25,9 @@ package com.fujieid.jap.core.exception; * @since 1.0.0 */ public class JapException extends RuntimeException { - /** - * Constructs a new runtime exception with {@code null} as its - * detail message. The cause is not initialized, and may subsequently be - * initialized by a call to {@link #initCause}. - */ - public JapException() { - } + + protected int errorCode; + protected String errorMessage; /** * Constructs a new runtime exception with the specified detail message. @@ -41,6 +39,21 @@ public class JapException extends RuntimeException { */ public JapException(String message) { super(message); + this.errorCode = JapErrorCode.ERROR.getErrroCode(); + this.errorMessage = message; + } + + /** + * Constructs a new runtime exception with the specified detail message. + * The cause is not initialized, and may subsequently be initialized by a + * call to {@link #initCause}. + * + * @param errorCode error code + */ + public JapException(JapErrorCode errorCode) { + super(errorCode.getErrorMessage()); + this.errorCode = errorCode.getErrroCode(); + this.errorMessage = errorCode.getErrorMessage(); } /** @@ -95,4 +108,12 @@ public class JapException extends RuntimeException { public JapException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } + + public int getErrorCode() { + return errorCode; + } + + public String getErrorMessage() { + return errorMessage; + } } diff --git a/jap-core/src/main/java/com/fujieid/jap/core/exception/JapOauth2Exception.java b/jap-core/src/main/java/com/fujieid/jap/core/exception/JapOauth2Exception.java index b873252..8a00a44 100644 --- a/jap-core/src/main/java/com/fujieid/jap/core/exception/JapOauth2Exception.java +++ b/jap-core/src/main/java/com/fujieid/jap/core/exception/JapOauth2Exception.java @@ -21,15 +21,6 @@ package com.fujieid.jap.core.exception; * @since 1.0.0 */ public class JapOauth2Exception extends JapException { - /** - * Constructs a new runtime exception with {@code null} as its - * detail message. The cause is not initialized, and may subsequently be - * initialized by a call to {@link #initCause}. - */ - public JapOauth2Exception() { - super(); - } - /** * Constructs a new runtime exception with the specified detail message. * The cause is not initialized, and may subsequently be initialized by a diff --git a/jap-core/src/main/java/com/fujieid/jap/core/exception/JapSocialException.java b/jap-core/src/main/java/com/fujieid/jap/core/exception/JapSocialException.java index 5dadc21..3157522 100644 --- a/jap-core/src/main/java/com/fujieid/jap/core/exception/JapSocialException.java +++ b/jap-core/src/main/java/com/fujieid/jap/core/exception/JapSocialException.java @@ -21,14 +21,6 @@ package com.fujieid.jap.core.exception; * @since 1.0.0 */ public class JapSocialException extends JapException { - /** - * Constructs a new runtime exception with {@code null} as its - * detail message. The cause is not initialized, and may subsequently be - * initialized by a call to {@link #initCause}. - */ - public JapSocialException() { - super(); - } /** * Constructs a new runtime exception with the specified detail message. diff --git a/jap-core/src/main/java/com/fujieid/jap/core/exception/OidcException.java b/jap-core/src/main/java/com/fujieid/jap/core/exception/OidcException.java index 9a23e9c..ab2ce9f 100644 --- a/jap-core/src/main/java/com/fujieid/jap/core/exception/OidcException.java +++ b/jap-core/src/main/java/com/fujieid/jap/core/exception/OidcException.java @@ -21,14 +21,6 @@ package com.fujieid.jap.core.exception; * @since 1.0.0 */ public class OidcException extends JapException { - /** - * Constructs a new runtime exception with {@code null} as its - * detail message. The cause is not initialized, and may subsequently be - * initialized by a call to {@link #initCause}. - */ - public OidcException() { - super(); - } /** * Constructs a new runtime exception with the specified detail message. diff --git a/jap-core/src/main/java/com/fujieid/jap/core/result/JapErrorCode.java b/jap-core/src/main/java/com/fujieid/jap/core/result/JapErrorCode.java new file mode 100644 index 0000000..e06a738 --- /dev/null +++ b/jap-core/src/main/java/com/fujieid/jap/core/result/JapErrorCode.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com). + *

+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.fujieid.jap.core.result; + +/** + * jap system error code + * + * @author yadong.zhang (yadong.zhang0415(a)gmail.com) + * @version 1.0.0 + * @since 1.0.0 + */ +public enum JapErrorCode { + /** + * jap system error code + */ + SUCCESS(200, "success."), + NOT_LOGGED_IN(401, "Not logged in."), + ERROR(500, "An error occurred in the system, please refer to the error message."), + NOT_EXIST_USER(1000, "The user does not exist."), + INVALID_PASSWORD(1001, "Passwords don't match."), + INVALID_MEMBERME_COOKIE(1002, "Illegal memberme cookie."), + UNABLE_SAVE_USERINFO(1003, "Unable to save user information."), + MISS_AUTH_CONFIG(1004, "AuthConfig in SocialStrategy is required."), + MISS_AUTHENTICATE_CONFIG(1005, "AuthenticateConfig is required."), + MISS_ISSUER(1006, "OidcStrategy requires a issuer option."), + MISS_CREDENTIALS(1007, "Missing credentials"), + ; + + private final int errroCode; + private final String errorMessage; + + JapErrorCode(int errroCode, String errorMessage) { + this.errroCode = errroCode; + this.errorMessage = errorMessage; + } + + public int getErrroCode() { + return errroCode; + } + + public String getErrorMessage() { + return errorMessage; + } +} diff --git a/jap-core/src/main/java/com/fujieid/jap/core/result/JapResponse.java b/jap-core/src/main/java/com/fujieid/jap/core/result/JapResponse.java new file mode 100644 index 0000000..cfb45de --- /dev/null +++ b/jap-core/src/main/java/com/fujieid/jap/core/result/JapResponse.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com). + *

+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.fujieid.jap.core.result; + +import java.io.Serializable; + +/** + * jap unified response class, standardized data return format. + * + * @author yadong.zhang (yadong.zhang0415(a)gmail.com) + * @version 1.0.0 + * @since 1.0.0 + */ +public class JapResponse implements Serializable { + private int code; + private String message; + private Object data; + + public static JapResponse success() { + return new JapResponse() + .setCode(JapErrorCode.SUCCESS.getErrroCode()) + .setMessage(JapErrorCode.SUCCESS.getErrorMessage()); + } + + public static JapResponse success(Object data) { + return new JapResponse() + .setCode(200) + .setData(data); + } + + public static JapResponse error(JapErrorCode errorCode) { + return new JapResponse() + .setCode(errorCode.getErrroCode()) + .setMessage(errorCode.getErrorMessage()); + } + + public static JapResponse error(int errorCode, String errorMessage) { + return new JapResponse() + .setCode(errorCode) + .setMessage(errorMessage); + } + + public boolean isSuccess() { + return this.getCode() == 200; + } + + public int getCode() { + return code; + } + + public JapResponse setCode(int code) { + this.code = code; + return this; + } + + public String getMessage() { + return message; + } + + public JapResponse setMessage(String message) { + this.message = message; + return this; + } + + public Object getData() { + return data; + } + + public JapResponse setData(Object data) { + this.data = data; + return this; + } +} diff --git a/jap-core/src/main/java/com/fujieid/jap/core/store/SessionJapUserStore.java b/jap-core/src/main/java/com/fujieid/jap/core/store/SessionJapUserStore.java index 08db811..aeb8fa2 100644 --- a/jap-core/src/main/java/com/fujieid/jap/core/store/SessionJapUserStore.java +++ b/jap-core/src/main/java/com/fujieid/jap/core/store/SessionJapUserStore.java @@ -18,6 +18,10 @@ package com.fujieid.jap.core.store; import cn.hutool.core.bean.BeanUtil; import com.fujieid.jap.core.JapConst; import com.fujieid.jap.core.JapUser; +import com.fujieid.jap.core.config.JapConfig; +import com.fujieid.jap.core.context.JapAuthentication; +import com.fujieid.jap.core.util.JapTokenHelper; +import com.fujieid.jap.core.util.JapUtil; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -30,6 +34,9 @@ import javax.servlet.http.HttpSession; */ public class SessionJapUserStore implements JapUserStore { + public SessionJapUserStore() { + } + /** * Login completed, save user information to the cache * @@ -44,6 +51,13 @@ public class SessionJapUserStore implements JapUserStore { JapUser newUser = BeanUtil.copyProperties(japUser, JapUser.class); newUser.setPassword(null); session.setAttribute(JapConst.SESSION_USER_KEY, newUser); + + JapConfig japConfig = JapAuthentication.getContext().getConfig(); + if (!japConfig.isSso()) { + String token = JapUtil.createToken(japUser, request); + new JapTokenHelper(JapAuthentication.getContext().getCache()).saveUserToken(japUser.getUserId(), token); + japUser.setToken(token); + } return japUser; } @@ -55,6 +69,15 @@ public class SessionJapUserStore implements JapUserStore { */ @Override public void remove(HttpServletRequest request, HttpServletResponse response) { + + JapConfig japConfig = JapAuthentication.getContext().getConfig(); + if (!japConfig.isSso()) { + JapUser japUser = this.get(request, response); + if (null != japUser) { + new JapTokenHelper(JapAuthentication.getContext().getCache()).removeUserToken(japUser.getUserId()); + } + } + HttpSession session = request.getSession(); session.removeAttribute(JapConst.SESSION_USER_KEY); session.invalidate(); diff --git a/jap-core/src/main/java/com/fujieid/jap/core/store/SsoJapUserStore.java b/jap-core/src/main/java/com/fujieid/jap/core/store/SsoJapUserStore.java index 62e2cd2..5a8455f 100644 --- a/jap-core/src/main/java/com/fujieid/jap/core/store/SsoJapUserStore.java +++ b/jap-core/src/main/java/com/fujieid/jap/core/store/SsoJapUserStore.java @@ -18,6 +18,8 @@ package com.fujieid.jap.core.store; import cn.hutool.core.util.StrUtil; import com.fujieid.jap.core.JapUser; import com.fujieid.jap.core.JapUserService; +import com.fujieid.jap.core.context.JapAuthentication; +import com.fujieid.jap.core.util.JapTokenHelper; import com.fujieid.jap.sso.JapSsoHelper; import com.fujieid.jap.sso.config.JapSsoConfig; @@ -57,9 +59,10 @@ public class SsoJapUserStore extends SessionJapUserStore { */ @Override public JapUser save(HttpServletRequest request, HttpServletResponse response, JapUser japUser) { - JapSsoHelper.login(japUser.getUserId(), japUser.getUsername(), this.japSsoConfig, request, response); + String token = JapSsoHelper.login(japUser.getUserId(), japUser.getUsername(), this.japSsoConfig, request, response); super.save(request, response, japUser); - return japUser; + new JapTokenHelper(JapAuthentication.getContext().getCache()).saveUserToken(japUser.getUserId(), token); + return japUser.setToken(token); } /** @@ -70,6 +73,10 @@ public class SsoJapUserStore extends SessionJapUserStore { */ @Override public void remove(HttpServletRequest request, HttpServletResponse response) { + JapUser japUser = this.get(request, response); + if(null != japUser) { + new JapTokenHelper(JapAuthentication.getContext().getCache()).removeUserToken(japUser.getUserId()); + } super.remove(request, response); JapSsoHelper.logout(request, response); } diff --git a/jap-core/src/main/java/com/fujieid/jap/core/strategy/AbstractJapStrategy.java b/jap-core/src/main/java/com/fujieid/jap/core/strategy/AbstractJapStrategy.java index 5404d58..3abe785 100644 --- a/jap-core/src/main/java/com/fujieid/jap/core/strategy/AbstractJapStrategy.java +++ b/jap-core/src/main/java/com/fujieid/jap/core/strategy/AbstractJapStrategy.java @@ -17,12 +17,18 @@ package com.fujieid.jap.core.strategy; import cn.hutool.core.util.ClassUtil; import cn.hutool.core.util.ObjectUtil; -import com.fujieid.jap.core.*; +import com.fujieid.jap.core.JapUser; +import com.fujieid.jap.core.JapUserService; import com.fujieid.jap.core.cache.JapCache; +import com.fujieid.jap.core.cache.JapCacheConfig; import com.fujieid.jap.core.cache.JapLocalCache; +import com.fujieid.jap.core.config.AuthenticateConfig; +import com.fujieid.jap.core.config.JapConfig; import com.fujieid.jap.core.context.JapAuthentication; import com.fujieid.jap.core.context.JapContext; import com.fujieid.jap.core.exception.JapException; +import com.fujieid.jap.core.result.JapErrorCode; +import com.fujieid.jap.core.result.JapResponse; import com.fujieid.jap.core.store.JapUserStore; import com.fujieid.jap.core.store.SessionJapUserStore; import com.fujieid.jap.core.store.SsoJapUserStore; @@ -78,6 +84,9 @@ public abstract class AbstractJapStrategy implements JapStrategy { JapAuthentication.setContext(this.japContext); + // Update the cache validity period + JapCacheConfig.timeout = japConfig.getCacheExpireTime(); + } /** @@ -87,18 +96,13 @@ public abstract class AbstractJapStrategy implements JapStrategy { * @param response Current response * @return boolean */ - protected boolean checkSession(HttpServletRequest request, HttpServletResponse response) { - JapUser sessionUser = japContext.getUserStore().get(request, response); - if (null != sessionUser) { - JapUtil.redirect(japContext.getConfig().getSuccessRedirect(), response); - return true; - } - return false; + protected JapUser checkSession(HttpServletRequest request, HttpServletResponse response) { + return japContext.getUserStore().get(request, response); } - protected void loginSuccess(JapUser japUser, HttpServletRequest request, HttpServletResponse response) { + protected JapResponse loginSuccess(JapUser japUser, HttpServletRequest request, HttpServletResponse response) { japContext.getUserStore().save(request, response, japUser); - JapUtil.redirect(japContext.getConfig().getSuccessRedirect(), response); + return JapResponse.success(japUser); } /** @@ -107,9 +111,9 @@ public abstract class AbstractJapStrategy implements JapStrategy { * @param sourceConfig The parameters passed in by the caller * @param targetConfigClazz The actual parameter class type */ - protected void checkAuthenticateConfig(AuthenticateConfig sourceConfig, Class targetConfigClazz) { + protected void checkAuthenticateConfig(AuthenticateConfig sourceConfig, Class targetConfigClazz) throws JapException { if (ObjectUtil.isNull(sourceConfig)) { - throw new JapException("AuthenticateConfig is required"); + throw new JapException(JapErrorCode.MISS_AUTHENTICATE_CONFIG); } if (!ClassUtil.isAssignable(sourceConfig.getClass(), targetConfigClazz)) { throw new JapException("Unsupported parameter type, please use " + ClassUtil.getClassName(targetConfigClazz, true) + ", a subclass of AuthenticateConfig"); diff --git a/jap-core/src/main/java/com/fujieid/jap/core/strategy/JapStrategy.java b/jap-core/src/main/java/com/fujieid/jap/core/strategy/JapStrategy.java index 73cd06a..a4a6ed6 100644 --- a/jap-core/src/main/java/com/fujieid/jap/core/strategy/JapStrategy.java +++ b/jap-core/src/main/java/com/fujieid/jap/core/strategy/JapStrategy.java @@ -15,8 +15,9 @@ */ package com.fujieid.jap.core.strategy; -import com.fujieid.jap.core.AuthenticateConfig; -import com.fujieid.jap.core.exception.JapStrategyException; +import com.fujieid.jap.core.config.AuthenticateConfig; +import com.fujieid.jap.core.result.JapErrorCode; +import com.fujieid.jap.core.result.JapResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -37,7 +38,7 @@ public interface JapStrategy { * @param request The request to authenticate * @param response The response to authenticate */ - default void authenticate(AuthenticateConfig config, HttpServletRequest request, HttpServletResponse response) { - throw new JapStrategyException("JapStrategy#authenticate must be overridden by subclass"); + default JapResponse authenticate(AuthenticateConfig config, HttpServletRequest request, HttpServletResponse response) { + return JapResponse.error(JapErrorCode.ERROR.getErrroCode(), "JapStrategy#authenticate(AuthenticateConfig, HttpServletRequest, HttpServletResponse) must be overridden by subclass"); } } diff --git a/jap-core/src/main/java/com/fujieid/jap/core/util/JapTokenHelper.java b/jap-core/src/main/java/com/fujieid/jap/core/util/JapTokenHelper.java new file mode 100644 index 0000000..a47fee7 --- /dev/null +++ b/jap-core/src/main/java/com/fujieid/jap/core/util/JapTokenHelper.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com). + *

+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.fujieid.jap.core.util; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.kisso.security.token.SSOToken; +import com.fujieid.jap.core.JapConst; +import com.fujieid.jap.core.cache.JapCache; +import com.fujieid.jap.sso.JapSsoUtil; + +import java.util.Map; + +/** + * jap user token helper, responsible for processing the token after the user logs in successfully + * + * @author yadong.zhang (yadong.zhang0415(a)gmail.com) + * @version 1.0.0 + * @since 1.0.0 + */ +public class JapTokenHelper { + + private final JapCache japCache; + + public JapTokenHelper(JapCache japCache) { + this.japCache = japCache; + } + + public void saveUserToken(String userId, String token) { + japCache.set(JapConst.USER_TOKEN_KEY.concat(userId), token); + } + + public String getUserToken(String userId) { + return (String) japCache.get(JapConst.USER_TOKEN_KEY.concat(userId)); + } + + public void removeUserToken(String userId) { + japCache.removeKey(JapConst.USER_TOKEN_KEY.concat(userId)); + } + + public Map checkToken(String token) { + SSOToken ssoToken = JapSsoUtil.parseToken(token); + if (ObjectUtil.isNull(ssoToken)) { + return null; + } + String cacheKey = JapConst.USER_TOKEN_KEY.concat(ssoToken.getId()); + if (!japCache.containsKey(cacheKey)) { + return null; + } + return ssoToken.getClaims(); + } +} diff --git a/jap-core/src/main/java/com/fujieid/jap/core/JapUtil.java b/jap-core/src/main/java/com/fujieid/jap/core/util/JapUtil.java similarity index 80% rename from jap-core/src/main/java/com/fujieid/jap/core/JapUtil.java rename to jap-core/src/main/java/com/fujieid/jap/core/util/JapUtil.java index f0bb90c..f564df3 100644 --- a/jap-core/src/main/java/com/fujieid/jap/core/JapUtil.java +++ b/jap-core/src/main/java/com/fujieid/jap/core/util/JapUtil.java @@ -13,10 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.fujieid.jap.core; +package com.fujieid.jap.core.util; +import com.fujieid.jap.core.JapUser; import com.fujieid.jap.core.exception.JapException; +import com.fujieid.jap.sso.JapSsoUtil; +import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @@ -31,10 +34,12 @@ public class JapUtil extends com.xkcoding.json.util.ObjectUtil { private static final String REDIRECT_ERROR = "JAP failed to redirect via HttpServletResponse."; + @Deprecated public static void redirect(String url, HttpServletResponse response) { redirect(url, REDIRECT_ERROR, response); } + @Deprecated public static void redirect(String url, String errorMessage, HttpServletResponse response) { try { response.sendRedirect(url); @@ -42,4 +47,8 @@ public class JapUtil extends com.xkcoding.json.util.ObjectUtil { throw new JapException(errorMessage, ex); } } + + public static String createToken(JapUser japUser, HttpServletRequest request) { + return JapSsoUtil.createToken(japUser.getUserId(), japUser.getUsername(), request); + } } diff --git a/jap-core/src/test/java/com/fujieid/jap/core/cache/JapLocalCacheTest.java b/jap-core/src/test/java/com/fujieid/jap/core/cache/JapLocalCacheTest.java index 1316ab4..8e335b8 100644 --- a/jap-core/src/test/java/com/fujieid/jap/core/cache/JapLocalCacheTest.java +++ b/jap-core/src/test/java/com/fujieid/jap/core/cache/JapLocalCacheTest.java @@ -62,7 +62,8 @@ public class JapLocalCacheTest { @Test public void getByNotEmptyKey() { JapCache japCache = new JapLocalCache(); - String res = (String) japCache.get("key"); + String res = (String) japCache.get("ke1y"); + System.out.println(res); Assert.assertNull(res); } diff --git a/jap-core/src/test/java/com/fujieid/jap/core/context/JapAuthenticationTest.java b/jap-core/src/test/java/com/fujieid/jap/core/context/JapAuthenticationTest.java new file mode 100644 index 0000000..81e7813 --- /dev/null +++ b/jap-core/src/test/java/com/fujieid/jap/core/context/JapAuthenticationTest.java @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com). + *

+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.fujieid.jap.core.context; + +import com.fujieid.jap.core.JapConst; +import com.fujieid.jap.core.JapUser; +import com.fujieid.jap.core.cache.JapCache; +import com.fujieid.jap.core.cache.JapLocalCache; +import com.fujieid.jap.core.config.JapConfig; +import com.fujieid.jap.core.result.JapResponse; +import com.fujieid.jap.core.store.JapUserStore; +import com.google.common.collect.Maps; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Map; + +public class JapAuthenticationTest { + @Mock + public HttpServletRequest httpServletRequestMock; + @Mock + public HttpServletResponse httpServletResponseMock; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void getContext() { + JapUserStore japUserStore = new JapUserStoreTest(); + JapCache japCache = new JapLocalCache(); + JapConfig japConfig = new JapConfig(); + JapContext japContext = new JapContext(japUserStore, japCache, japConfig); + JapAuthentication.setContext(japContext); + Assert.assertNotNull(JapAuthentication.getContext()); + } + + @Test + public void setContext() { + JapUserStore japUserStore = new JapUserStoreTest(); + JapCache japCache = new JapLocalCache(); + JapConfig japConfig = new JapConfig(); + JapContext japContext = new JapContext(japUserStore, japCache, japConfig); + JapAuthentication.setContext(japContext); + } + + @Test + public void getNullUser() { + JapUserStore japUserStore = new JapUserStoreTest(); + JapCache japCache = new JapLocalCache(); + JapConfig japConfig = new JapConfig(); + JapContext japContext = new JapContext(japUserStore, japCache, japConfig); + JapAuthentication.setContext(japContext); + + JapUser japUser = JapAuthentication.getContext().getUserStore().get(httpServletRequestMock, httpServletResponseMock); + Assert.assertNull(japUser); + } + + @Test + public void getUser() { + JapUserStore japUserStore = new JapUserStoreTest(); + JapCache japCache = new JapLocalCache(); + JapConfig japConfig = new JapConfig(); + JapContext japContext = new JapContext(japUserStore, japCache, japConfig); + JapAuthentication.setContext(japContext); + + JapAuthentication.getContext().getUserStore().save(httpServletRequestMock, httpServletResponseMock, new JapUser()); + JapUser japUser = JapAuthentication.getContext().getUserStore().get(httpServletRequestMock, httpServletResponseMock); + Assert.assertNotNull(japUser); + } + + @Test + public void getUserNullStore() { + JapUserStore japUserStore = null; + JapCache japCache = new JapLocalCache(); + JapConfig japConfig = new JapConfig(); + JapContext japContext = new JapContext(japUserStore, japCache, japConfig); + JapAuthentication.setContext(japContext); + + JapUser japUser = JapAuthentication.getUser(httpServletRequestMock, httpServletResponseMock); + Assert.assertNull(japUser); + } + + @Test + public void checkNullUser() { + JapUserStore japUserStore = new JapUserStoreTest(); + JapCache japCache = new JapLocalCache(); + JapConfig japConfig = new JapConfig(); + JapContext japContext = new JapContext(japUserStore, japCache, japConfig); + JapAuthentication.setContext(japContext); + + JapResponse response = JapAuthentication.checkUser(httpServletRequestMock, httpServletResponseMock); + Assert.assertEquals(response.getCode(), 401); + } + + @Test + public void checkUser() { + JapUserStore japUserStore = new JapUserStoreTest(); + JapCache japCache = new JapLocalCache(); + JapConfig japConfig = new JapConfig(); + JapContext japContext = new JapContext(japUserStore, japCache, japConfig); + JapAuthentication.setContext(japContext); + + JapAuthentication.getContext().getUserStore().save(httpServletRequestMock, httpServletResponseMock, new JapUser()); + JapResponse response = JapAuthentication.checkUser(httpServletRequestMock, httpServletResponseMock); + Assert.assertEquals(response.getCode(), 200); + } + + @Test + public void checkTokenNullContext() { + Map map = JapAuthentication.checkToken("aaa"); + Assert.assertNull(map); + } + + @Test + public void checkTokenNullCache() { + JapUserStore japUserStore = new JapUserStoreTest(); + JapCache japCache = null; + JapConfig japConfig = new JapConfig(); + JapContext japContext = new JapContext(japUserStore, japCache, japConfig); + JapAuthentication.setContext(japContext); + + Map map = JapAuthentication.checkToken("aaa"); + Assert.assertNull(map); + } + + @Test + public void checkTokenNullToken() { + JapUserStore japUserStore = new JapUserStoreTest(); + JapCache japCache = new JapLocalCache(); + JapConfig japConfig = new JapConfig(); + JapContext japContext = new JapContext(japUserStore, japCache, japConfig); + JapAuthentication.setContext(japContext); + + Map map = JapAuthentication.checkToken(null); + Assert.assertNull(map); + } + + @Test + public void checkTokenNotInCache() { + JapUserStore japUserStore = new JapUserStoreTest(); + JapCache japCache = new JapLocalCache(); + JapConfig japConfig = new JapConfig(); + JapContext japContext = new JapContext(japUserStore, japCache, japConfig); + JapAuthentication.setContext(japContext); + String cacheKey = JapConst.USER_TOKEN_KEY.concat("1111"); + japCache.removeKey(cacheKey); + Map map = JapAuthentication.checkToken("eyJhbGciOiJIUzUxMiJ9.eyJqdGkiOiIxMTExIiwiaXAiOiIxOTIuMTY4LjEuMTAzIiwiaXNzIjoiamFwIiwidWEiOiJiM2VmOSIsImlhdCI6MTYxNDY3NjA2N30.MK6CBJR98y6UnRBy2coHXrxNJU4N4bZIA05oCgkaNYODdfSRwXhUEqV-OqYsushOxNmUYH0Lp6sKAtrBip0yCw"); + System.out.println(map); + Assert.assertNull(map); + } + + @Test + public void checkToken() { + JapUserStore japUserStore = new JapUserStoreTest(); + JapCache japCache = new JapLocalCache(); + JapConfig japConfig = new JapConfig(); + JapContext japContext = new JapContext(japUserStore, japCache, japConfig); + JapAuthentication.setContext(japContext); + + String token = "eyJhbGciOiJIUzUxMiJ9.eyJqdGkiOiIxMTExIiwiaXAiOiIxOTIuMTY4LjEuMTAzIiwiaXNzIjoiamFwIiwidWEiOiJiM2VmOSIsImlhdCI6MTYxNDY3NjA2N30.MK6CBJR98y6UnRBy2coHXrxNJU4N4bZIA05oCgkaNYODdfSRwXhUEqV-OqYsushOxNmUYH0Lp6sKAtrBip0yCw"; + String cacheKey = JapConst.USER_TOKEN_KEY.concat("1111"); + japCache.set(cacheKey, token); + Map map = JapAuthentication.checkToken(token); + System.out.println(map); + Assert.assertEquals("{jti=1111, ip=192.168.1.103, iss=jap, ua=b3ef9, iat=1614676067}", map.toString()); + } + + @Test + public void logout() { + JapUserStore japUserStore = new JapUserStoreTest(); + JapCache japCache = new JapLocalCache(); + JapConfig japConfig = new JapConfig(); + JapContext japContext = new JapContext(japUserStore, japCache, japConfig); + JapAuthentication.setContext(japContext); + + boolean result = JapAuthentication.logout(httpServletRequestMock, httpServletResponseMock); + Assert.assertTrue(result); + } + + @Test + public void logoutNullStore() { + JapUserStore japUserStore = null; + JapCache japCache = new JapLocalCache(); + JapConfig japConfig = new JapConfig(); + JapContext japContext = new JapContext(japUserStore, japCache, japConfig); + JapAuthentication.setContext(japContext); + + boolean result = JapAuthentication.logout(httpServletRequestMock, httpServletResponseMock); + Assert.assertFalse(result); + } + + static class JapUserStoreTest implements JapUserStore { + Map STORE = Maps.newHashMap(); + String USER_KEY = "user"; + + /** + * Login completed, save user information to the cache + * + * @param request current request + * @param response current response + * @param japUser User information after successful login + * @return JapUser + */ + @Override + public JapUser save(HttpServletRequest request, HttpServletResponse response, JapUser japUser) { + STORE.put(USER_KEY, japUser); + return japUser; + } + + /** + * Clear user information from cache + * + * @param request current request + * @param response current response + */ + @Override + public void remove(HttpServletRequest request, HttpServletResponse response) { + STORE.remove(USER_KEY); + } + + /** + * Get the login user information from the cache, return {@code JapUser} if it exists, + * return {@code null} if it is not logged in or the login has expired + * + * @param request current request + * @param response current response + * @return JapUser + */ + @Override + public JapUser get(HttpServletRequest request, HttpServletResponse response) { + return (JapUser) STORE.get(USER_KEY); + } + } +} diff --git a/jap-core/src/test/java/com/fujieid/jap/core/util/JapUtilTest.java b/jap-core/src/test/java/com/fujieid/jap/core/util/JapUtilTest.java new file mode 100644 index 0000000..e0f607b --- /dev/null +++ b/jap-core/src/test/java/com/fujieid/jap/core/util/JapUtilTest.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com). + *

+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.fujieid.jap.core.util; + +import com.fujieid.jap.core.JapUser; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import javax.servlet.http.HttpServletRequest; + +import static org.mockito.Mockito.when; + +public class JapUtilTest { + @Mock + public HttpServletRequest httpServletRequestMock; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void createToken() { + when(httpServletRequestMock.getHeader("x-forwarded-for")).thenReturn("127.0.0.1"); + when(httpServletRequestMock.getHeader("user-agent")).thenReturn("ua"); + String token = JapUtil.createToken(new JapUser() + .setUserId("11111") + .setUsername("username"), httpServletRequestMock); + Assert.assertNotNull(token); + } +} -- GitLab