提交 1ed36a41 编写于 作者: 智布道's avatar 智布道 👁

🔖 pre-releasing 1.0.1-alpha

上级 b568c88b
......@@ -5,7 +5,7 @@
<parent>
<groupId>com.fujieid</groupId>
<artifactId>jap</artifactId>
<version>1.0.1</version>
<version>1.0.1-alpha</version>
</parent>
<modelVersion>4.0.0</modelVersion>
......
......@@ -28,6 +28,8 @@ public interface JapConst {
String SESSION_USER_KEY = "_jap:session:user";
String USER_TOKEN_KEY = "_jap:user:token:";
/**
* default delimiter
*/
......
......@@ -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;
}
}
......@@ -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<String, Object> userInfo, Object tokenInfo) {
throw new JapUserException("JapUserService#createAndGetOauth2User(String, Map<String, Object>, Object) must be overridden by subclass");
return null;
}
}
......@@ -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);
}
......@@ -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);
}
......@@ -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);
}
}
......@@ -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.
......
......@@ -13,10 +13,12 @@
* 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;
import com.fujieid.jap.sso.config.JapSsoConfig;
import java.util.concurrent.TimeUnit;
/**
* Jap configuration.
*
......@@ -26,16 +28,6 @@ import com.fujieid.jap.sso.config.JapSsoConfig;
*/
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
*/
......@@ -47,37 +39,14 @@ public class JapConfig {
private JapSsoConfig ssoConfig;
/**
* After successful login, redirect to {@code successRedirect}. Default is `/`
* After the user logs in successfully, the valid time of the token, in milliseconds, the default validity period is 7 days
*/
private String successRedirect = "/";
private long tokenExpireTime = TimeUnit.DAYS.toMillis(7);
/**
* After logout, redirect to {@code logoutRedirect}. Default is `/`
* The expiration time of the jap cache, in milliseconds, the default validity period is 7 days
*/
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;
}
private long cacheExpireTime = TimeUnit.DAYS.toMillis(7);
public boolean isSso() {
return sso;
......@@ -97,30 +66,21 @@ public class JapConfig {
return this;
}
public String getSuccessRedirect() {
return successRedirect;
}
public JapConfig setSuccessRedirect(String successRedirect) {
this.successRedirect = successRedirect;
return this;
}
public String getFailureRedirect() {
return failureRedirect;
public long getTokenExpireTime() {
return tokenExpireTime;
}
public JapConfig setFailureRedirect(String failureRedirect) {
this.failureRedirect = failureRedirect;
public JapConfig setTokenExpireTime(long tokenExpireTime) {
this.tokenExpireTime = tokenExpireTime;
return this;
}
public String getLogoutRedirect() {
return logoutRedirect;
public long getCacheExpireTime() {
return cacheExpireTime;
}
public JapConfig setLogoutRedirect(String logoutRedirect) {
this.logoutRedirect = logoutRedirect;
public JapConfig setCacheExpireTime(long cacheExpireTime) {
this.cacheExpireTime = cacheExpireTime;
return this;
}
}
......@@ -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:
* <p>
* <p>
* <code>
* if(!JapAuthentication.checkUser(request, response).isSuccess()) { <br/>
* // Not logged in.<br/>
* }<br/>
* </code>
* <p>
* <p>
* Is equivalent to the following code:
* <p>
* <p>
* <code>
* JapUser japUser = JapAuthentication.getUser(request, response);<br/>
* if (null == japUser) {<br/>
* // Not logged in.<br/>
* }<br/>
* </code>
*
* @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<String, Object> checkToken(String token) {
if (null == context || ObjectUtil.isEmpty(token)) {
return null;
}
JapCache japCache = context.getCache();
if (null == japCache) {
return null;
}
Map<String, Object> 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<String, Cookie> 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;
}
}
......@@ -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;
......
......@@ -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;
}
}
......@@ -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
......
......@@ -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.
......
......@@ -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.
......
/*
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
* <p>
* 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
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* 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;
}
}
/*
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
* <p>
* 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
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* 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;
}
}
......@@ -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();
......
......@@ -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);
}
......
......@@ -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");
......
......@@ -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");
}
}
/*
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
* <p>
* 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
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* 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<String, Object> 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();
}
}
......@@ -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);
}
}
......@@ -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);
}
......
/*
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
* <p>
* 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
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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);
}
}
}
/*
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
* <p>
* 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
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* 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);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册