From 4a57348a6d182650e38bf69243c147e5b772eee1 Mon Sep 17 00:00:00 2001 From: Parker Date: Wed, 30 Dec 2020 17:34:32 +0800 Subject: [PATCH] =?UTF-8?q?=E6=89=A9=E5=B1=95=E7=99=BB=E5=BD=95=E6=96=B9?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../opsli/common/constants/SignConstants.java | 25 ++-- .../common/constants/TokenTypeConstants.java | 16 +++ .../java/org/opsli/core/conf/ShiroConfig.java | 57 ++++++--- .../org/opsli/core/conf/SwaggerConfig.java | 7 +- .../core/handler/GlobalExceptionHandler.java | 14 +++ .../java/org/opsli/core/msg/TokenMsg.java | 4 +- .../CustomModularRealmAuthenticator.java | 44 +++++++ .../shiro/filter/CustomShiroFilter.java | 108 ++++++++++++++++++ .../security/shiro/realm/ExternalRealm.java | 54 +++++++++ .../core/security/shiro/realm/FlagRealm.java | 11 ++ .../security/shiro/realm/OAuth2Realm.java | 2 +- .../{JwtToken.java => ExternalToken.java} | 12 +- .../security/shiro/token/OAuth2Token.java | 4 +- .../java/org/opsli/core/utils/JwtUtil.java | 8 +- .../opsli/core/utils/SpringContextHolder.java | 35 +++++- .../org/opsli/core/utils/UserTokenUtil.java | 3 +- 16 files changed, 356 insertions(+), 48 deletions(-) create mode 100644 opsli-base-support/opsli-common/src/main/java/org/opsli/common/constants/TokenTypeConstants.java create mode 100644 opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/authenticator/CustomModularRealmAuthenticator.java create mode 100644 opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/filter/CustomShiroFilter.java create mode 100644 opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/realm/ExternalRealm.java create mode 100644 opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/realm/FlagRealm.java rename opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/token/{JwtToken.java => ExternalToken.java} (64%) diff --git a/opsli-base-support/opsli-common/src/main/java/org/opsli/common/constants/SignConstants.java b/opsli-base-support/opsli-common/src/main/java/org/opsli/common/constants/SignConstants.java index 7b4a3bd1..17b3577c 100644 --- a/opsli-base-support/opsli-common/src/main/java/org/opsli/common/constants/SignConstants.java +++ b/opsli-base-support/opsli-common/src/main/java/org/opsli/common/constants/SignConstants.java @@ -1,24 +1,7 @@ -/** - * Copyright 2020 OPSLI 快速开发平台 https://www.opsli.com - *

- * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * 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 org.opsli.common.constants; /** - * @BelongsProject: opsli-boot - * @BelongsPackage: org.opsli.common.constants - * @Author: Parker + * @Author: 周鹏程 * @CreateTime: 2020-09-16 17:42 * @Description: 签名 */ @@ -33,4 +16,10 @@ public interface SignConstants { /** 时间戳 */ String TIMESTAMP = "timestamp"; + /** 其他信息 */ + String OTHER = "other"; + + /** 签名 类型 */ + String TYPE = "type"; + } diff --git a/opsli-base-support/opsli-common/src/main/java/org/opsli/common/constants/TokenTypeConstants.java b/opsli-base-support/opsli-common/src/main/java/org/opsli/common/constants/TokenTypeConstants.java new file mode 100644 index 00000000..18099dd9 --- /dev/null +++ b/opsli-base-support/opsli-common/src/main/java/org/opsli/common/constants/TokenTypeConstants.java @@ -0,0 +1,16 @@ +package org.opsli.common.constants; + +/** + * @Author: 周鹏程 + * @CreateTime: 2020-09-16 17:42 + * @Description: Token类型 + */ +public interface TokenTypeConstants { + + /** 系统内部TOKEN */ + String TYPE_SYSTEM = "system"; + + /** 外部TOKEN */ + String TYPE_EXTERNAL = "external"; + +} diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/conf/ShiroConfig.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/conf/ShiroConfig.java index 514cb7d1..809815dd 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/conf/ShiroConfig.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/conf/ShiroConfig.java @@ -16,8 +16,13 @@ package org.opsli.core.conf; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ClassUtil; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy; +import org.apache.shiro.authc.pam.ModularRealmAuthenticator; import org.apache.shiro.mgt.SecurityManager; +import org.apache.shiro.realm.Realm; import org.apache.shiro.session.mgt.SessionManager; import org.apache.shiro.spring.LifecycleBeanPostProcessor; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; @@ -25,21 +30,21 @@ import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; import org.opsli.common.utils.Props; -import org.opsli.core.security.shiro.filter.OAuth2Filter; -import org.opsli.core.security.shiro.realm.OAuth2Realm; +import org.opsli.core.security.shiro.authenticator.CustomModularRealmAuthenticator; +import org.opsli.core.security.shiro.filter.CustomShiroFilter; +import org.opsli.core.security.shiro.realm.FlagRealm; import org.opsli.plugins.redis.conf.RedisPluginConfig; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; -import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import javax.servlet.Filter; -import java.util.HashMap; -import java.util.LinkedHashMap; +import java.lang.reflect.Modifier; import java.util.List; import java.util.Map; +import java.util.Set; /** * Shiro配置 @@ -76,7 +81,7 @@ public class ShiroConfig { //oauth过滤 Map filters = Maps.newHashMapWithExpectedSize(1); - filters.put("oauth2", new OAuth2Filter()); + filters.put("last_filter", new CustomShiroFilter()); shiroFilter.setFilters(filters); Map filterMap = Maps.newLinkedHashMap(); @@ -106,7 +111,7 @@ public class ShiroConfig { filterMap.put("/swagger-ui.html", "anon"); filterMap.put("/swagger-resources/**", "anon"); filterMap.put("/static/file/**", "anon"); - filterMap.put("/**", "oauth2"); + filterMap.put("/**", "last_filter"); shiroFilter.setFilterChainDefinitionMap(filterMap); @@ -122,16 +127,42 @@ public class ShiroConfig { } @Bean("securityManager") - public DefaultWebSecurityManager securityManager(OAuth2Realm oAuth2Realm, SessionManager sessionManager,LettuceConnectionFactory lettuceConnectionFactory) { + public DefaultWebSecurityManager securityManager(SessionManager sessionManager) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); - securityManager.setRealm(oAuth2Realm); securityManager.setSessionManager(sessionManager); + + List realms = Lists.newArrayList(); + // 拿到state包下 实现了 FlagRealm 接口的,所有子类 + Set> clazzSet = ClassUtil.scanPackageBySuper(FlagRealm.class.getPackage().getName() + , FlagRealm.class + ); + for (Class aClass : clazzSet) { + // 位运算 去除抽象类 + if((aClass.getModifiers() & Modifier.ABSTRACT) != 0){ + continue; + } + + try { + realms.add((Realm) aClass.newInstance()); + } catch (Exception ignored){ } + } + + if(CollUtil.isNotEmpty(realms)){ + // 追加 Realms + securityManager.setRealms(realms); + } + return securityManager; } - @Bean - public OAuth2Realm oAuth2Realm() { - return new OAuth2Realm(); + /** + * 针对多Realm,使用自定义身份验证器 + */ + @Bean("modularRealmAuthenticator") + public ModularRealmAuthenticator modularRealmAuthenticator(){ + CustomModularRealmAuthenticator authenticator = new CustomModularRealmAuthenticator(); + authenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy()); + return authenticator; } @@ -157,7 +188,7 @@ public class ShiroConfig { /** * 开启shiro权限注解生效 - * @param securityManager + * @param securityManager 安全管理器 * @return */ @Bean("authorizationAttributeSourceAdvisor") diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/conf/SwaggerConfig.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/conf/SwaggerConfig.java index 544c0913..f3077da0 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/conf/SwaggerConfig.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/conf/SwaggerConfig.java @@ -21,6 +21,7 @@ import com.google.common.collect.Lists; import io.swagger.annotations.ApiOperation; import org.opsli.core.utils.UserTokenUtil; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @@ -47,6 +48,10 @@ import java.util.List; @Import(BeanValidatorPluginsConfiguration.class) public class SwaggerConfig { + /** 系统名称 */ + @Value("${opsli.system-name:OPSLI 快速开发平台}") + private String systemName; + private final TypeResolver typeResolver; @Autowired @@ -87,7 +92,7 @@ public class SwaggerConfig { private ApiInfo apiInfo() { return new ApiInfoBuilder() // //大标题 - .title("Opsli-Boot 后台服务API接口文档") + .title(systemName + " 服务API接口文档") // 版本号 .version("1.0") // 描述 diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/handler/GlobalExceptionHandler.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/handler/GlobalExceptionHandler.java index f4dc438a..fdecff44 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/handler/GlobalExceptionHandler.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/handler/GlobalExceptionHandler.java @@ -20,6 +20,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.LockedAccountException; +import org.apache.shiro.authc.pam.UnsupportedTokenException; import org.apache.shiro.authz.AuthorizationException; import org.opsli.api.base.result.ResultVo; import org.opsli.common.exception.*; @@ -143,6 +144,19 @@ public class GlobalExceptionHandler { ); } + /** + * 拦截 自定义 Shiro 认证异常 + */ + @ExceptionHandler(UnsupportedTokenException.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + @ResponseBody + public ResultVo unsupportedTokenException(UnsupportedTokenException e) { + // 找不到认证授权器 + return ResultVo.error(TokenMsg.EXCEPTION_NOT_REALM.getCode(), + TokenMsg.EXCEPTION_NOT_REALM.getMessage() + ); + } + /** * 拦截 自定义 Token 认证异常 diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/msg/TokenMsg.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/msg/TokenMsg.java index b146f168..07aec728 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/msg/TokenMsg.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/msg/TokenMsg.java @@ -52,7 +52,9 @@ public enum TokenMsg implements BaseMsg { * 其他 */ EXCEPTION_USER_NULL(12200, "用户为空"), - EXCEPTION_NOT_AUTH(12204, "无权访问该方法"), + EXCEPTION_NOT_AUTH(12201, "无权访问该方法"), + EXCEPTION_NOT_REALM(12202, "找不到认证授权器"), + ; private final int code; diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/authenticator/CustomModularRealmAuthenticator.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/authenticator/CustomModularRealmAuthenticator.java new file mode 100644 index 00000000..6010447d --- /dev/null +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/authenticator/CustomModularRealmAuthenticator.java @@ -0,0 +1,44 @@ +package org.opsli.core.security.shiro.authenticator; + +import org.apache.shiro.authc.AuthenticationInfo; +import org.apache.shiro.authc.AuthenticationToken; +import org.apache.shiro.authc.pam.ModularRealmAuthenticator; +import org.apache.shiro.authc.pam.UnsupportedTokenException; +import org.apache.shiro.realm.Realm; + +import java.util.Collection; + +/** + * 自定义身份验证器,根据登录使用的Token匹配调用对应的Realm + * @author Parker + */ +public class CustomModularRealmAuthenticator extends ModularRealmAuthenticator { + + /** + * 自定义Realm的分配策略 + * 通过realm.supports()方法匹配对应的Realm,因此才要在Realm中重写supports()方法 + * @param realms + * @param token + * @return + */ + @Override + protected AuthenticationInfo doMultiRealmAuthentication(Collection realms, AuthenticationToken token) { + // 判断getRealms()是否返回为空 + assertRealmsConfigured(); + + // 通过supports()方法,匹配对应的Realm + Realm uniqueRealm = null; + for (Realm realm : realms) { + if (realm.supports(token)) { + uniqueRealm = realm; + break; + } + } + + if (uniqueRealm == null) { + throw new UnsupportedTokenException(); + } + return uniqueRealm.getAuthenticationInfo(token); + } + +} diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/filter/CustomShiroFilter.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/filter/CustomShiroFilter.java new file mode 100644 index 00000000..9106e2f6 --- /dev/null +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/filter/CustomShiroFilter.java @@ -0,0 +1,108 @@ +package org.opsli.core.security.shiro.filter; + + +import org.apache.commons.lang3.StringUtils; +import org.apache.shiro.authc.AuthenticationException; +import org.apache.shiro.authc.AuthenticationToken; +import org.apache.shiro.web.filter.authc.AuthenticatingFilter; +import org.opsli.api.base.result.ResultVo; +import org.opsli.common.constants.SignConstants; +import org.opsli.common.constants.TokenTypeConstants; +import org.opsli.core.msg.TokenMsg; +import org.opsli.core.security.shiro.token.ExternalToken; +import org.opsli.core.security.shiro.token.OAuth2Token; +import org.opsli.core.utils.JwtUtil; +import org.opsli.core.utils.UserTokenUtil; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * oauth2过滤器 + * + * 就是因为,以前单机,页面的挑转自己能控制,失败的时候定一个错误码:401, + * + * 集中登录,集中授权, + * + * @author 孙志强 + + * @date 2017-05-20 13:00 + */ +public class CustomShiroFilter extends AuthenticatingFilter { + + @Override + protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception { + //获取请求token + String token = UserTokenUtil.getRequestToken((HttpServletRequest) request); + + if(StringUtils.isBlank(token)){ + return null; + } + + // 分析token + String claim = JwtUtil.getClaim(token, SignConstants.TYPE); + + // 第三方登录 + if(TokenTypeConstants.TYPE_EXTERNAL.equals(claim)){ + return new ExternalToken(token); + } + // .... 追加登录方式 + + return new OAuth2Token(token); + } + + @Override + protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { + if(((HttpServletRequest) request).getMethod().equals(RequestMethod.OPTIONS.name())){ + return true; + } + // remeberMe ,remeberMe特殊页面,需要授权, + + return false; + } + + @Override + protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { + HttpServletRequest httpServletRequest = (HttpServletRequest) request; + //获取请求token,如果token不存在,直接返回401 + String token = UserTokenUtil.getRequestToken((HttpServletRequest) request); + if(StringUtils.isBlank(token)){ + HttpServletResponse httpResponse = (HttpServletResponse) response; + httpResponse.setHeader("Access-Control-Allow-Credentials", "true"); + httpResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE"); + httpResponse.setHeader("Access-Control-Allow-Origin", httpServletRequest.getHeader("Origin")); + httpResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers")); + httpResponse.setContentType("application/json; charset=utf-8"); + // 401 Token失效,请重新登录 + ResultVo error = ResultVo.error(TokenMsg.EXCEPTION_TOKEN_LOSE_EFFICACY.getCode(), + TokenMsg.EXCEPTION_TOKEN_LOSE_EFFICACY.getMessage()); + httpResponse.getWriter().print(error.toJsonStr()); + return false; + } + + return executeLogin(request, response); + } + + @Override + protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) { + HttpServletRequest httpServletRequest = (HttpServletRequest) request; + HttpServletResponse httpResponse = (HttpServletResponse) response; + httpResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE"); + httpResponse.setHeader("Access-Control-Allow-Origin", httpServletRequest.getHeader("Origin")); + httpResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers")); + httpResponse.setContentType("application/json; charset=utf-8"); + + try { + //处理登录失败的异常 + Throwable throwable = e.getCause() == null ? e : e.getCause(); + ResultVo error = ResultVo.error(401, throwable.getMessage()); + httpResponse.getWriter().print(error.toJsonStr()); + } catch (IOException ignored) {} + return false; + } + +} diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/realm/ExternalRealm.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/realm/ExternalRealm.java new file mode 100644 index 00000000..16f9b81d --- /dev/null +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/realm/ExternalRealm.java @@ -0,0 +1,54 @@ +package org.opsli.core.security.shiro.realm; + +import lombok.extern.slf4j.Slf4j; +import org.apache.shiro.authc.AuthenticationException; +import org.apache.shiro.authc.AuthenticationInfo; +import org.apache.shiro.authc.AuthenticationToken; +import org.apache.shiro.authz.AuthorizationInfo; +import org.apache.shiro.realm.AuthorizingRealm; +import org.apache.shiro.subject.PrincipalCollection; +import org.opsli.common.exception.TokenException; +import org.opsli.core.security.shiro.token.ExternalToken; +import org.springframework.stereotype.Component; + + +/** + * 对外接口 认证 + * + * @author 周鹏程 + + * @date 2020-12-29 14:00 + */ +@Component +@Slf4j +public class ExternalRealm extends AuthorizingRealm implements FlagRealm { + + /** 账号锁定状态 */ + public static final char LOCK_VAL = '1'; + + @Override + public boolean supports(AuthenticationToken token) { + return token instanceof ExternalToken; + } + + /** + * 授权(验证权限时调用) + */ + @Override + protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { + // TODO 待处理 + return null; + } + + /** + * 对外认证(登录时调用) + */ + @Override + protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) + throws AuthenticationException, TokenException { + // TODO 待处理 + + return null; + } + +} diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/realm/FlagRealm.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/realm/FlagRealm.java new file mode 100644 index 00000000..69a41b2e --- /dev/null +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/realm/FlagRealm.java @@ -0,0 +1,11 @@ +package org.opsli.core.security.shiro.realm; + +/** + * @BelongsProject: think-bboss-parent + * @BelongsPackage: com.think.bboss.core.shiro.realm + * @Author: Parker + * @CreateTime: 2020-12-29 20:10 + * @Description: Realm 识别类 勿删 + */ +public interface FlagRealm { +} diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/realm/OAuth2Realm.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/realm/OAuth2Realm.java index 5c56f8f8..b146d748 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/realm/OAuth2Realm.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/realm/OAuth2Realm.java @@ -30,7 +30,7 @@ import java.util.List; */ @Component @Slf4j -public class OAuth2Realm extends AuthorizingRealm { +public class OAuth2Realm extends AuthorizingRealm implements FlagRealm { /** 账号锁定状态 */ public static final String LOCK_VAL = "1"; diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/token/JwtToken.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/token/ExternalToken.java similarity index 64% rename from opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/token/JwtToken.java rename to opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/token/ExternalToken.java index 44885300..5f48a854 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/token/JwtToken.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/token/ExternalToken.java @@ -4,16 +4,17 @@ package org.opsli.core.security.shiro.token; import org.apache.shiro.authc.AuthenticationToken; /** - * jwt token + * 第三方接口 token * - * @author parker + * @author 周鹏程 * @date 2017-05-20 13:22 */ -public class JwtToken implements AuthenticationToken { - private String token; +public class ExternalToken implements AuthenticationToken { - public JwtToken(String token){ + private final String token; + + public ExternalToken(String token){ this.token = token; } @@ -26,4 +27,5 @@ public class JwtToken implements AuthenticationToken { public Object getCredentials() { return token; } + } diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/token/OAuth2Token.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/token/OAuth2Token.java index 061ae7e9..951074ca 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/token/OAuth2Token.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/token/OAuth2Token.java @@ -11,7 +11,8 @@ import org.apache.shiro.authc.AuthenticationToken; * @date 2017-05-20 13:22 */ public class OAuth2Token implements AuthenticationToken { - private String token; + + private final String token; public OAuth2Token(String token){ this.token = token; @@ -26,4 +27,5 @@ public class OAuth2Token implements AuthenticationToken { public Object getCredentials() { return token; } + } diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/JwtUtil.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/JwtUtil.java index 70143e95..0598e160 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/JwtUtil.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/JwtUtil.java @@ -8,6 +8,7 @@ import com.auth0.jwt.exceptions.JWTDecodeException; import com.auth0.jwt.interfaces.DecodedJWT; import lombok.extern.slf4j.Slf4j; import org.opsli.common.constants.SignConstants; +import org.opsli.common.constants.TokenTypeConstants; import org.opsli.common.exception.JwtException; import org.opsli.common.utils.Props; import org.opsli.core.msg.JwtMsg; @@ -79,10 +80,12 @@ public final class JwtUtil { /** * 生成签名 + * @param tokenType token类型 * @param account 帐号 + * @param userId 用户ID * @return java.lang.String 返回加密的Token */ - public static String sign(String account, String userId) { + public static String sign(String tokenType, String account, String userId) { try { // 帐号加JWT私钥加密 String secret = account + Base64ConvertUtil.decode(ENCRYPT_JWT_KEY); @@ -91,6 +94,7 @@ public final class JwtUtil { Algorithm algorithm = Algorithm.HMAC256(secret); // 附带account帐号信息 return JWT.create() + .withClaim(SignConstants.TYPE, tokenType) .withClaim(SignConstants.ACCOUNT, account) .withClaim(SignConstants.USER_ID, userId) .withClaim(SignConstants.TIMESTAMP, String.valueOf(System.currentTimeMillis())) @@ -106,7 +110,7 @@ public final class JwtUtil { public static void main(String[] args) { - String aaaaaa = JwtUtil.sign("aaaaaa","123123"); + String aaaaaa = JwtUtil.sign(TokenTypeConstants.TYPE_SYSTEM, "aaaaaa","123123"); boolean verify = JwtUtil.verify(aaaaaa); System.out.println(aaaaaa); diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/SpringContextHolder.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/SpringContextHolder.java index 8d629fbe..34bbb63d 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/SpringContextHolder.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/SpringContextHolder.java @@ -5,15 +5,20 @@ import org.apache.commons.lang3.Validate; import org.springframework.beans.factory.DisposableBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Lazy; +import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; + /** - * 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候取出ApplicaitonContext. + * 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候取出ApplicationContext. * + * 针对项目 启动后好使, 项目启动前 Bean注册时不好使 * @author Zaric * @date 2016-5-29 下午1:25:40 */ +@Order(-1) @Component @Lazy(false) @Slf4j @@ -21,7 +26,6 @@ public class SpringContextHolder implements ApplicationContextAware, DisposableB private static ApplicationContext applicationContext = null; - /** * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型. */ @@ -39,6 +43,27 @@ public class SpringContextHolder implements ApplicationContextAware, DisposableB return applicationContext.getBean(requiredType); } + /** + * 注册Bean对象 + * @param beanName beanName + * @param bean bean对象 + * @param 泛型 + */ + public static boolean registerBean(String beanName, T bean) { + assertContextInjected(); + boolean ret = false; + ConfigurableApplicationContext context = (ConfigurableApplicationContext) applicationContext; + if(context != null){ + try { + context.getBeanFactory().registerSingleton(beanName, bean); + ret = true; + }catch (Exception e){ + log.error(e.getMessage(), e); + } + } + return ret; + } + /** * 清除SpringContextHolder中的ApplicationContext为Null. */ @@ -50,12 +75,11 @@ public class SpringContextHolder implements ApplicationContextAware, DisposableB } - /** * 检查ApplicationContext不为空. */ private static void assertContextInjected() { - Validate.validState(applicationContext != null, "applicaitonContext属性未注入, 请在applicationContext.xml中定义SpringContextHolder."); + Validate.validState(applicationContext != null, "applicationContext属性未注入."); } // ================== @@ -72,8 +96,9 @@ public class SpringContextHolder implements ApplicationContextAware, DisposableB * 实现DisposableBean接口, 在Context关闭时清理静态变量. */ @Override - public void destroy() throws Exception { + public void destroy(){ SpringContextHolder.clearHolder(); } } + diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserTokenUtil.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserTokenUtil.java index 4a274f9a..4537ce02 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserTokenUtil.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserTokenUtil.java @@ -29,6 +29,7 @@ import org.opsli.api.wrapper.system.user.UserModel; import org.opsli.common.constants.CacheConstants; import org.opsli.common.constants.SignConstants; import org.opsli.common.constants.TokenConstants; +import org.opsli.common.constants.TokenTypeConstants; import org.opsli.common.exception.ServiceException; import org.opsli.common.exception.TokenException; import org.opsli.common.utils.Props; @@ -116,7 +117,7 @@ public class UserTokenUtil { ); // 生成 Token 包含 username userId timestamp - String signToken = JwtUtil.sign(user.getUsername(), user.getId()); + String signToken = JwtUtil.sign(TokenTypeConstants.TYPE_SYSTEM, user.getUsername(), user.getId()); // 生成MD5 16进制码 用于缩减存储 String signTokenHex = new Md5Hash(signToken).toHex();