From 8ee845c16cfbe666b1b01174471c614be60b96a5 Mon Sep 17 00:00:00 2001 From: kdyzm Date: Mon, 11 Jan 2021 11:25:19 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E8=AE=A4=E8=AF=81=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E9=A2=81=E5=8F=91jwt=20token?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/center/config/AuthorizationServer.java | 15 ++++++++++++--- .../security/auth/center/config/TokenConfig.java | 15 ++++++++++++++- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/auth-center/src/main/java/com/kdyzm/spring/security/auth/center/config/AuthorizationServer.java b/auth-center/src/main/java/com/kdyzm/spring/security/auth/center/config/AuthorizationServer.java index e36bdc9..030c7bf 100644 --- a/auth-center/src/main/java/com/kdyzm/spring/security/auth/center/config/AuthorizationServer.java +++ b/auth-center/src/main/java/com/kdyzm/spring/security/auth/center/config/AuthorizationServer.java @@ -14,9 +14,11 @@ import org.springframework.security.oauth2.config.annotation.web.configurers.Aut import org.springframework.security.oauth2.provider.ClientDetailsService; import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices; import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices; -import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices; -import org.springframework.security.oauth2.provider.token.DefaultTokenServices; -import org.springframework.security.oauth2.provider.token.TokenStore; +import org.springframework.security.oauth2.provider.token.*; +import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; + +import java.util.Arrays; +import java.util.Collections; /** * @author kdyzm @@ -37,6 +39,9 @@ public class AuthorizationServer extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; + @Autowired + private JwtAccessTokenConverter jwtAccessTokenConverter; + @Bean public AuthorizationServerTokenServices tokenServices(){ DefaultTokenServices services = new DefaultTokenServices(); @@ -45,6 +50,10 @@ public class AuthorizationServer extends AuthorizationServerConfigurerAdapter { services.setTokenStore(tokenStore); services.setAccessTokenValiditySeconds(7200); services.setRefreshTokenValiditySeconds(259200); + + TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain(); + tokenEnhancerChain.setTokenEnhancers(Collections.singletonList(jwtAccessTokenConverter)); + services.setTokenEnhancer(tokenEnhancerChain); return services; } diff --git a/auth-center/src/main/java/com/kdyzm/spring/security/auth/center/config/TokenConfig.java b/auth-center/src/main/java/com/kdyzm/spring/security/auth/center/config/TokenConfig.java index 0f3b177..c07d2dc 100644 --- a/auth-center/src/main/java/com/kdyzm/spring/security/auth/center/config/TokenConfig.java +++ b/auth-center/src/main/java/com/kdyzm/spring/security/auth/center/config/TokenConfig.java @@ -2,8 +2,11 @@ package com.kdyzm.spring.security.auth.center.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.security.jwt.Jwt; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore; +import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; +import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; /** * @author kdyzm @@ -11,8 +14,18 @@ import org.springframework.security.oauth2.provider.token.store.InMemoryTokenSto @Configuration public class TokenConfig { + private static final String SIGNING_KEY = "auth123"; + @Bean public TokenStore tokenStore() { - return new InMemoryTokenStore(); + return new JwtTokenStore(accessTokenConverter()); + } + + + @Bean + public JwtAccessTokenConverter accessTokenConverter(){ + JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter(); + jwtAccessTokenConverter.setSigningKey(SIGNING_KEY);//对称秘钥,资源服务器使用该秘钥来验证 + return jwtAccessTokenConverter; } } -- Gitee From a4961f9c3ffe6fbf7971db00902ab31f3505be99 Mon Sep 17 00:00:00 2001 From: kdyzm Date: Mon, 11 Jan 2021 16:28:40 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E5=88=9B=E5=BB=BAcommon=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E6=8F=90=E4=BE=9B=E5=85=AC=E5=85=B1=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- auth-center/pom.xml | 6 + .../security/auth/center/config/Config.java | 13 ++ common/pom.xml | 41 +++++ .../study/common/AccessLogInterceptor.java | 158 ++++++++++++++++++ .../study/common/config/ApiWebMvcConfig.java | 25 +++ pom.xml | 1 + resource-server/pom.xml | 6 + .../study/resource/server/config/Config.java | 12 ++ 8 files changed, 262 insertions(+) create mode 100644 auth-center/src/main/java/com/kdyzm/spring/security/auth/center/config/Config.java create mode 100644 common/pom.xml create mode 100644 common/src/main/java/com/kdyzm/spring/security/oauth/study/common/AccessLogInterceptor.java create mode 100644 common/src/main/java/com/kdyzm/spring/security/oauth/study/common/config/ApiWebMvcConfig.java create mode 100644 resource-server/src/main/java/com/kdyzm/spring/security/oauth/study/resource/server/config/Config.java diff --git a/auth-center/pom.xml b/auth-center/pom.xml index 67280ed..40b4bdb 100644 --- a/auth-center/pom.xml +++ b/auth-center/pom.xml @@ -66,6 +66,12 @@ org.springframework.boot spring-boot-starter-thymeleaf + + com.kdyzm.spring.security.oauth.study + common + 1.0-SNAPSHOT + compile + \ No newline at end of file diff --git a/auth-center/src/main/java/com/kdyzm/spring/security/auth/center/config/Config.java b/auth-center/src/main/java/com/kdyzm/spring/security/auth/center/config/Config.java new file mode 100644 index 0000000..7e6e3d2 --- /dev/null +++ b/auth-center/src/main/java/com/kdyzm/spring/security/auth/center/config/Config.java @@ -0,0 +1,13 @@ +package com.kdyzm.spring.security.auth.center.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +/** + * @author kdyzm + */ +@Configuration +@Import({com.kdyzm.spring.security.oauth.study.common.config.ApiWebMvcConfig.class}) +public class Config { + +} diff --git a/common/pom.xml b/common/pom.xml new file mode 100644 index 0000000..3960733 --- /dev/null +++ b/common/pom.xml @@ -0,0 +1,41 @@ + + + + spring-security-oauth-study + com.kdyzm.spring.security.oauth.study + 1.0-SNAPSHOT + + 4.0.0 + + common + + + org.springframework + spring-context + 5.1.5.RELEASE + compile + + + org.springframework + spring-webmvc + 5.1.5.RELEASE + compile + + + org.slf4j + slf4j-api + 1.7.25 + compile + + + org.apache.tomcat.embed + tomcat-embed-core + 9.0.16 + compile + + + + + \ No newline at end of file diff --git a/common/src/main/java/com/kdyzm/spring/security/oauth/study/common/AccessLogInterceptor.java b/common/src/main/java/com/kdyzm/spring/security/oauth/study/common/AccessLogInterceptor.java new file mode 100644 index 0000000..5403968 --- /dev/null +++ b/common/src/main/java/com/kdyzm/spring/security/oauth/study/common/AccessLogInterceptor.java @@ -0,0 +1,158 @@ +package com.kdyzm.spring.security.oauth.study.common; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.regex.Pattern; + +/** + * @author kdyzm + */ +@Component +public class AccessLogInterceptor implements HandlerInterceptor { + + private static final Logger ACCESS_LOG = LoggerFactory.getLogger("ACCESS"); + + private static final String SEPARATOR = " "; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, + Object handler) { + return true; + } + + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { + + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, + Object handler, Exception ex) { + //domain & uri & refer + String domain = request.getServerName(); + String uri = request.getRequestURI(); + String refer = request.getHeader("Referer"); + final String token = request.getHeader("x-auth-token"); + final String installation_ID = request.getHeader("Installation-ID"); + + //traceId + String traceId = request.getHeader("X-B3-TraceId"); + if (StringUtils.isEmpty(traceId)) { + traceId = UUID.randomUUID().toString(); + } + MDC.put("X-B3-TraceId", traceId); + + String remoteIp = getRemoteAddr(request); + String userAgent = request.getHeader("User-Agent"); + Map paramPair = getRequestParamValueMap(request); + + printAccesslog(traceId, remoteIp, "", "", domain, uri, refer, userAgent, paramPair); + } + + //打印access log + private void printAccesslog(String traceId, String remoteIp, String userId, String userName, + String domain, String uri, String refer, + String userAgent, Map paramPair) { + + StringBuilder sb = new StringBuilder(); + + long timestamp = System.currentTimeMillis(); + sb.append(SEPARATOR).append(timestamp); + sb.append(SEPARATOR).append(remoteIp); +// sb.append(SEPARATOR).append(userId); +// sb.append(SEPARATOR).append(userName); + //RequestId用于定位access log与业务log + sb.append(SEPARATOR).append(traceId); + sb.append(SEPARATOR).append(domain); + sb.append(SEPARATOR).append(uri); + sb.append(SEPARATOR).append(refer); + sb.append(SEPARATOR).append(userAgent); + //将参数map打印成json格式,利于统计分析 + sb.append(SEPARATOR); + + ACCESS_LOG.info(sb.toString()); + } + + private String getRemoteAddr(HttpServletRequest request) { + String ip; + @SuppressWarnings("unchecked") + Enumeration xffs = request.getHeaders("X-Forwarded-For"); + if (xffs.hasMoreElements()) { + String xff = xffs.nextElement(); + ip = resolveClientIPFromXFF(xff); + if (isValidIP(ip)) { + return ip; + } + } + ip = request.getHeader("Proxy-Client-IP"); + if (isValidIP(ip)) { + return ip; + } + ip = request.getHeader("WL-Proxy-Client-IP"); + if (isValidIP(ip)) { + return ip; + } + return request.getRemoteAddr(); + } + + /** + * 从X-Forwarded-For头部中获取客户端的真实IP。 X-Forwarded-For并不是RFC定义的标准HTTP请求Header + * ,可以参考http://en.wikipedia.org/wiki/X-Forwarded-For + * + * @param xff X-Forwarded-For头部的值 + * @return 如果能够解析到client IP,则返回表示该IP的字符串,否则返回null + */ + private String resolveClientIPFromXFF(String xff) { + if (xff == null || xff.isEmpty()) { + return null; + } + String[] ss = xff.split(","); + for (int i = ss.length - 1; i >= 0; i--) {// x-forward-for链反向遍历 + String ip = ss[i].trim(); + if (isValidIP(ip)) { + return ip; + } + } + + return null; + } + + private static final Pattern ipPattern = Pattern.compile("([0-9]{1,3}\\.){3}[0-9]{1,3}"); + + private boolean isValidIP(String ip) { + if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { + return false; + } + return ipPattern.matcher(ip).matches(); + } + + private Map getRequestParamValueMap(HttpServletRequest request) { + Map param2value = new HashMap<>(); + Enumeration e = request.getParameterNames(); + String param; + + while(e.hasMoreElements()) { + param = (String)e.nextElement(); + if(param != null) { + String value = request.getParameter(param); + if(value != null) { + param2value.put(param, value); + } + } + } + + return param2value; + } +} diff --git a/common/src/main/java/com/kdyzm/spring/security/oauth/study/common/config/ApiWebMvcConfig.java b/common/src/main/java/com/kdyzm/spring/security/oauth/study/common/config/ApiWebMvcConfig.java new file mode 100644 index 0000000..ed841e5 --- /dev/null +++ b/common/src/main/java/com/kdyzm/spring/security/oauth/study/common/config/ApiWebMvcConfig.java @@ -0,0 +1,25 @@ +package com.kdyzm.spring.security.oauth.study.common.config; + + +import com.kdyzm.spring.security.oauth.study.common.AccessLogInterceptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * @author kdyzm + */ +@Configuration +@ComponentScan(basePackages = {"com.kdyzm.spring.security.oauth.study.common"}) +public class ApiWebMvcConfig implements WebMvcConfigurer { + + @Autowired + private AccessLogInterceptor accessLogInterceptor; + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(accessLogInterceptor).addPathPatterns("/**"); + } +} diff --git a/pom.xml b/pom.xml index 285a5b3..fbd8912 100644 --- a/pom.xml +++ b/pom.xml @@ -12,6 +12,7 @@ register-center auth-center resource-server + common diff --git a/resource-server/pom.xml b/resource-server/pom.xml index b65ed73..3f04f96 100644 --- a/resource-server/pom.xml +++ b/resource-server/pom.xml @@ -36,6 +36,12 @@ org.projectlombok lombok + + com.kdyzm.spring.security.oauth.study + common + 1.0-SNAPSHOT + compile + \ No newline at end of file diff --git a/resource-server/src/main/java/com/kdyzm/spring/security/oauth/study/resource/server/config/Config.java b/resource-server/src/main/java/com/kdyzm/spring/security/oauth/study/resource/server/config/Config.java new file mode 100644 index 0000000..48d6512 --- /dev/null +++ b/resource-server/src/main/java/com/kdyzm/spring/security/oauth/study/resource/server/config/Config.java @@ -0,0 +1,12 @@ +package com.kdyzm.spring.security.oauth.study.resource.server.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +/** + * @author kdyzm + */ +@Configuration +@Import({com.kdyzm.spring.security.oauth.study.common.config.ApiWebMvcConfig.class}) +public class Config { +} -- Gitee From 54667917ec9468f9b960ea7e7961fd0358254ac0 Mon Sep 17 00:00:00 2001 From: kdyzm Date: Mon, 11 Jan 2021 16:29:08 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E8=B5=84=E6=BA=90=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E4=BD=BF=E7=94=A8jwt=E4=BB=A4=E7=89=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/config/ResouceServerConfig.java | 27 ++++++++++------- .../resource/server/config/TokenConfig.java | 29 +++++++++++++++++++ 2 files changed, 45 insertions(+), 11 deletions(-) create mode 100644 resource-server/src/main/java/com/kdyzm/spring/security/oauth/study/resource/server/config/TokenConfig.java diff --git a/resource-server/src/main/java/com/kdyzm/spring/security/oauth/study/resource/server/config/ResouceServerConfig.java b/resource-server/src/main/java/com/kdyzm/spring/security/oauth/study/resource/server/config/ResouceServerConfig.java index a36118d..d86ff35 100644 --- a/resource-server/src/main/java/com/kdyzm/spring/security/oauth/study/resource/server/config/ResouceServerConfig.java +++ b/resource-server/src/main/java/com/kdyzm/spring/security/oauth/study/resource/server/config/ResouceServerConfig.java @@ -11,6 +11,7 @@ import org.springframework.security.oauth2.config.annotation.web.configuration.R import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; import org.springframework.security.oauth2.provider.token.RemoteTokenServices; import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices; +import org.springframework.security.oauth2.provider.token.TokenStore; /** * @author kdyzm @@ -22,22 +23,26 @@ public class ResouceServerConfig extends ResourceServerConfigurerAdapter { private static final String RESOURCE_ID= "r1"; @Autowired - private ResourceServerTokenServices resourceServerTokenServices; - - @Bean - public ResourceServerTokenServices resourceServerTokenServices(){ - RemoteTokenServices remoteTokenServices = new RemoteTokenServices(); - remoteTokenServices.setCheckTokenEndpointUrl("http://127.0.0.1:30000/oauth/check_token"); - remoteTokenServices.setClientId("c1"); - remoteTokenServices.setClientSecret("secret"); - return remoteTokenServices; - } + private TokenStore tokenStore; + +// @Autowired +// private ResourceServerTokenServices resourceServerTokenServices; + +// @Bean +// public ResourceServerTokenServices resourceServerTokenServices(){ +// RemoteTokenServices remoteTokenServices = new RemoteTokenServices(); +// remoteTokenServices.setCheckTokenEndpointUrl("http://127.0.0.1:30000/oauth/check_token"); +// remoteTokenServices.setClientId("c1"); +// remoteTokenServices.setClientSecret("secret"); +// return remoteTokenServices; +// } @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources .resourceId(RESOURCE_ID) - .tokenServices(resourceServerTokenServices)//令牌服务 +// .tokenServices(resourceServerTokenServices)//令牌服务 + .tokenStore(tokenStore) .stateless(true); } diff --git a/resource-server/src/main/java/com/kdyzm/spring/security/oauth/study/resource/server/config/TokenConfig.java b/resource-server/src/main/java/com/kdyzm/spring/security/oauth/study/resource/server/config/TokenConfig.java new file mode 100644 index 0000000..2802bb1 --- /dev/null +++ b/resource-server/src/main/java/com/kdyzm/spring/security/oauth/study/resource/server/config/TokenConfig.java @@ -0,0 +1,29 @@ +package com.kdyzm.spring.security.oauth.study.resource.server.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.oauth2.provider.token.TokenStore; +import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; +import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; + +/** + * @author kdyzm + */ +@Configuration +public class TokenConfig { + + private static final String SIGNING_KEY = "auth123"; + + @Bean + public TokenStore tokenStore() { + return new JwtTokenStore(accessTokenConverter()); + } + + + @Bean + public JwtAccessTokenConverter accessTokenConverter(){ + JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter(); + jwtAccessTokenConverter.setSigningKey(SIGNING_KEY);//对称秘钥,资源服务器使用该秘钥来验证 + return jwtAccessTokenConverter; + } +} -- Gitee