From ed9885bf857c994875b4fbb240ed9fe029a46e41 Mon Sep 17 00:00:00 2001 From: zhuyijun Date: Sat, 15 Oct 2022 14:09:41 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=8E=88=E6=9D=83=E7=A0=81?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 9 +- .../cn/zyjblogs/config/redis/RedisConfig.java | 75 +++++ ...OAuth2AccessTokenJackson2Deserializer.java | 61 ++++ .../OAuth2AccessTokenJackson2Serializer.java | 72 +++++ .../serializer/OAuth2AccessTokenMixIn.java | 9 + ...th2AuthenticationJackson2Deserializer.java | 182 +++++++++++ .../serializer/OAuth2AuthenticationMixin.java | 14 + .../AuthorizationServerConfiguration.java | 14 +- .../security/OauthAccessTokenConverter.java | 3 +- .../config/security/ResourceServerConfig.java | 9 +- .../security/WebSecurityConfiguration.java | 1 + .../OauthAuthorizationCodeServices.java | 54 ++++ .../user/controller/AuthController.java | 4 +- .../server/user/dto/AuthorizationCodeDto.java | 5 + .../server/user/dto/AuthorizationDto.java | 101 ++++++ .../server/user/po/OauthUserDetails.java | 5 +- .../server/user/service/AuthService.java | 2 +- .../user/service/impl/AuthServiceImpl.java | 291 +++++++++++++++++- .../pom.xml | 2 + .../constant/CommonRedisKeyConstant.java | 7 + .../common/entity/context/BaseContext.java | 7 +- .../starter/common/entity/dto/ContextDto.java | 1 + .../pom.xml | 2 + .../pom.xml | 2 + .../pom.xml | 2 + .../token/OauthAccessTokenConverter.java | 6 +- .../pom.xml | 2 + .../pom.xml | 2 + .../GenericJackson2JsonRedisSerializerEx.java | 40 +-- ...disConfig.java => RedisConfiguration.java} | 36 +-- .../redis/utils/RedisTemplateHandler.java | 89 +++--- .../main/resources/META-INF/spring.factories | 2 +- .../zyjblogs-web-spring-boot-starter/pom.xml | 2 + .../ApiVersionWebMvcAutoConfiguration.java | 7 + .../Knife4jAutoConfigurationConfig.java | 34 +- 35 files changed, 999 insertions(+), 155 deletions(-) create mode 100644 server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/redis/RedisConfig.java create mode 100644 server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/redis/serializer/OAuth2AccessTokenJackson2Deserializer.java create mode 100644 server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/redis/serializer/OAuth2AccessTokenJackson2Serializer.java create mode 100644 server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/redis/serializer/OAuth2AccessTokenMixIn.java create mode 100644 server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/redis/serializer/OAuth2AuthenticationJackson2Deserializer.java create mode 100644 server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/redis/serializer/OAuth2AuthenticationMixin.java create mode 100644 server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/policy/OauthAuthorizationCodeServices.java create mode 100644 server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/dto/AuthorizationDto.java rename stater/zyjblogs-redis-spring-boot-starter/src/main/java/cn/zyjblogs/starter/redis/config/{RedisConfig.java => RedisConfiguration.java} (56%) diff --git a/pom.xml b/pom.xml index 0952d36..6d95c7a 100644 --- a/pom.xml +++ b/pom.xml @@ -38,7 +38,6 @@ 11.8 2.13.3 - 2.13.3 2.0.11 3.4.3 @@ -68,7 +67,8 @@ 1.1.0 3.0.3 - + + UTF-8 @@ -170,11 +170,6 @@ nacos-client ${nacos-client.version} - - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 - ${jackson-datatype-jsr310.version} - com.alibaba diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/redis/RedisConfig.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/redis/RedisConfig.java new file mode 100644 index 0000000..095fda4 --- /dev/null +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/redis/RedisConfig.java @@ -0,0 +1,75 @@ +package cn.zyjblogs.config.redis; + +import cn.zyjblogs.config.redis.serializer.OAuth2AccessTokenMixIn; +import cn.zyjblogs.config.redis.serializer.OAuth2AuthenticationMixin; +import cn.zyjblogs.starter.redis.config.GenericJackson2JsonRedisSerializerEx; +import cn.zyjblogs.starter.redis.config.RedisConfiguration; +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.security.jackson2.CoreJackson2Module; +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.security.web.jackson2.WebJackson2Module; + +/** + * RedisConfig + * + * @author zhuyijun + */ + +@Configuration( + proxyBeanMethods = false +) +@AutoConfigureAfter(RedisConfiguration.class) +public class RedisConfig { + + /** + * Redis配置 + * 针对key、value、hashKey、hashValue做序列化 + * + * @return org.springframework.data.redis.core.RedisTemplate + */ + @Bean + @SuppressWarnings("all") + public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(redisConnectionFactory); + ObjectMapper om = new ObjectMapper(); + om.registerModule(new JavaTimeModule()); + om.registerModule(new CoreJackson2Module()); + om.registerModule(new WebJackson2Module()); + + om.addMixIn(OAuth2AccessToken.class, OAuth2AccessTokenMixIn.class); + om.addMixIn(OAuth2Authentication.class, OAuth2AuthenticationMixin.class); + om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + // 序列化时添加类型,否则反序列化时会报错,无法转换 + om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, + JsonTypeInfo.As.PROPERTY); + + // 反序列化时候遇到不匹配的属性并不抛出异常 忽略json字符串中不识别的属性 + om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + // 序列化时候遇到空对象不抛出异常 忽略无法转换的对象 “No serializer found for class com.xxx.xxx” + om.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + GenericJackson2JsonRedisSerializerEx genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializerEx(om); + + //序列号key value + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer); + redisTemplate.setHashKeySerializer(new StringRedisSerializer()); + redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer); + redisTemplate.afterPropertiesSet(); + return redisTemplate; + } +} diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/redis/serializer/OAuth2AccessTokenJackson2Deserializer.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/redis/serializer/OAuth2AccessTokenJackson2Deserializer.java new file mode 100644 index 0000000..3b495cb --- /dev/null +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/redis/serializer/OAuth2AccessTokenJackson2Deserializer.java @@ -0,0 +1,61 @@ +package cn.zyjblogs.config.redis.serializer; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; +import org.springframework.security.oauth2.common.DefaultOAuth2RefreshToken; +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.common.util.OAuth2Utils; + +import java.io.IOException; +import java.util.Date; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +public final class OAuth2AccessTokenJackson2Deserializer extends StdDeserializer { + + Logger logger = LoggerFactory.getLogger(OAuth2AccessTokenJackson2Deserializer.class); + + private static final long serialVersionUID = 1L; + + public OAuth2AccessTokenJackson2Deserializer() { + super(OAuth2AccessToken.class); + } + + @Override + public OAuth2AccessToken deserialize(JsonParser jp, DeserializationContext ctxt) + throws IOException, JsonProcessingException { + Map additionalInformation = new LinkedHashMap(); + ObjectMapper mapper = (ObjectMapper) jp.getCodec(); + JsonNode jsonNode = mapper.readTree(jp); + String tokenValue = jsonNode.get(OAuth2AccessToken.ACCESS_TOKEN).asText(); + String tokenType = jsonNode.get(OAuth2AccessToken.TOKEN_TYPE).asText(); + Integer expiresIn = jsonNode.get(OAuth2AccessToken.EXPIRES_IN).asInt(); + String refreshToken = jsonNode.get(OAuth2AccessToken.REFRESH_TOKEN) == null ? null + : jsonNode.get(OAuth2AccessToken.REFRESH_TOKEN).asText(); + String scopeText = jsonNode.get(OAuth2AccessToken.SCOPE).asText(); + Set scope = OAuth2Utils.parseParameterList(scopeText); + + // TODO What should occur if a required parameter (tokenValue or tokenType) is missing? + + DefaultOAuth2AccessToken accessToken = new DefaultOAuth2AccessToken(tokenValue); + accessToken.setTokenType(tokenType); + if (expiresIn != null) { + accessToken.setExpiration(new Date(System.currentTimeMillis() + (expiresIn * 1000))); + } + if (refreshToken != null) { + accessToken.setRefreshToken(new DefaultOAuth2RefreshToken(refreshToken)); + } + accessToken.setScope(scope); + accessToken.setAdditionalInformation(additionalInformation); + + return accessToken; + } +} diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/redis/serializer/OAuth2AccessTokenJackson2Serializer.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/redis/serializer/OAuth2AccessTokenJackson2Serializer.java new file mode 100644 index 0000000..45bed1f --- /dev/null +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/redis/serializer/OAuth2AccessTokenJackson2Serializer.java @@ -0,0 +1,72 @@ +package cn.zyjblogs.config.redis.serializer; + +import com.fasterxml.jackson.core.JsonGenerationException; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.jsontype.TypeSerializer; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.common.OAuth2RefreshToken; +import org.springframework.util.Assert; + +import java.io.IOException; +import java.util.Date; +import java.util.Map; +import java.util.Set; + +public class OAuth2AccessTokenJackson2Serializer extends StdSerializer { + + private static final long serialVersionUID = 1L; + + public OAuth2AccessTokenJackson2Serializer() { + super(OAuth2AccessToken.class); + } + + @Override + public void serializeWithType(OAuth2AccessToken value, JsonGenerator gen, SerializerProvider serializers, + TypeSerializer typeSer) throws IOException { + // TODO Auto-generated method stub + extracted(value, gen, serializers, typeSer); + } + + @Override + public void serialize(OAuth2AccessToken token, JsonGenerator jgen, SerializerProvider serializers) + throws IOException, JsonGenerationException { + extracted(token, jgen, serializers, null); + } + + private void extracted(OAuth2AccessToken token, JsonGenerator jgen, SerializerProvider serializers, + TypeSerializer typeSer) throws IOException { + jgen.writeStartObject(); + if (typeSer != null) { + jgen.writeStringField(typeSer.getPropertyName(), token.getClass().getName()); + } + jgen.writeStringField(OAuth2AccessToken.ACCESS_TOKEN, token.getValue()); + jgen.writeStringField(OAuth2AccessToken.TOKEN_TYPE, token.getTokenType()); + OAuth2RefreshToken refreshToken = token.getRefreshToken(); + if (refreshToken != null) { + jgen.writeStringField(OAuth2AccessToken.REFRESH_TOKEN, refreshToken.getValue()); + } + Date expiration = token.getExpiration(); + if (expiration != null) { + long now = System.currentTimeMillis(); + jgen.writeNumberField(OAuth2AccessToken.EXPIRES_IN, (expiration.getTime() - now) / 1000); + } + Set scope = token.getScope(); + if (scope != null && !scope.isEmpty()) { + StringBuffer scopes = new StringBuffer(); + for (String s : scope) { + Assert.hasLength(s, "Scopes cannot be null or empty. Got " + scope + ""); + scopes.append(s); + scopes.append(" "); + } + jgen.writeStringField(OAuth2AccessToken.SCOPE, scopes.substring(0, scopes.length() - 1)); + } + Map additionalInformation = token.getAdditionalInformation(); + for (String key : additionalInformation.keySet()) { + jgen.writeObjectField(key, additionalInformation.get(key)); + } + jgen.writeEndObject(); + } + +} diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/redis/serializer/OAuth2AccessTokenMixIn.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/redis/serializer/OAuth2AccessTokenMixIn.java new file mode 100644 index 0000000..f8de9b1 --- /dev/null +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/redis/serializer/OAuth2AccessTokenMixIn.java @@ -0,0 +1,9 @@ +package cn.zyjblogs.config.redis.serializer; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) +@com.fasterxml.jackson.databind.annotation.JsonSerialize(using = OAuth2AccessTokenJackson2Serializer.class) +@com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = OAuth2AccessTokenJackson2Deserializer.class) +public class OAuth2AccessTokenMixIn { +} diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/redis/serializer/OAuth2AuthenticationJackson2Deserializer.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/redis/serializer/OAuth2AuthenticationJackson2Deserializer.java new file mode 100644 index 0000000..a3014c5 --- /dev/null +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/redis/serializer/OAuth2AuthenticationJackson2Deserializer.java @@ -0,0 +1,182 @@ +package cn.zyjblogs.config.redis.serializer; + +import cn.zyjblogs.server.user.po.OauthUserDetails; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.node.MissingNode; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.security.oauth2.provider.OAuth2Request; +import org.springframework.security.oauth2.provider.TokenRequest; +import org.springframework.util.StringUtils; + +import java.io.IOException; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +public class OAuth2AuthenticationJackson2Deserializer extends StdDeserializer { + protected OAuth2AuthenticationJackson2Deserializer() { + super(OAuth2Authentication.class); + } + + public OAuth2AuthenticationJackson2Deserializer(Class vc) { + super(vc); + } + + private static String readString(ObjectMapper mapper, JsonNode jsonNode) { + return readValue(mapper, jsonNode, String.class); + } + + private static T readValue(ObjectMapper mapper, JsonNode jsonNode, Class clazz) { + if (mapper == null || jsonNode == null || clazz == null) { + return null; + } + try { + return mapper.readValue(jsonNode.traverse(), clazz); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static T readValue(ObjectMapper mapper, JsonNode jsonNode, TypeReference type) { + if (mapper == null || jsonNode == null || type == null) { + return null; + } + try { + return mapper.readValue(jsonNode.traverse(), type); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public OAuth2Authentication deserialize(JsonParser jp, DeserializationContext ctxt) + throws IOException { + ObjectMapper mapper = (ObjectMapper) jp.getCodec(); + JsonNode jsonNode = mapper.readTree(jp); + JsonNode requestNode = readJsonNode(jsonNode, "oauth2Request"); + JsonNode userAuthenticationNode = readJsonNode(jsonNode, "userAuthentication"); + + Authentication authentication = parseAuthentication(mapper, userAuthenticationNode); + OAuth2Request request = parseOAuth2Request(mapper, requestNode); + return new OAuth2Authentication(request, authentication); + } + + /** + * 解析Authentication + * + * @param mapper + * @param json + * @return + * @author zhuyijun + * @date 2022/10/15 + */ + private Authentication parseAuthentication(ObjectMapper mapper, JsonNode json) { + if (mapper == null || json == null) { + return null; + } + OauthUserDetails principal = parseOAuth2User(mapper, json.get("principal")); + Object credentials = readValue(mapper, json.get("credentials"), Object.class); + Collection grantedAuthorities = parseSimpleGrantedAuthorities(mapper, json.get("authorities")); + return new UsernamePasswordAuthenticationToken(principal, credentials, grantedAuthorities); + } + + private OauthUserDetails parseOAuth2User(ObjectMapper mapper, JsonNode json) { + if (mapper == null || json == null) { + return null; + } + String id = readString(mapper, json.get("id")); + String username = readString(mapper, json.get("username")); + String password = readString(mapper, json.get("password")); + String tenantId = readString(mapper, json.get("tenantId")); + String name = readString(mapper, json.get("name")); + String phone = readString(mapper, json.get("phone")); + String email = readString(mapper, json.get("email")); + Boolean accountNonExpired = readValue(mapper, json.get("accountNonExpired"), Boolean.class); + Boolean accountNonLocked = readValue(mapper, json.get("accountNonLocked"), Boolean.class); + Boolean credentialsNonExpired = readValue(mapper, json.get("credentialsNonExpired"), Boolean.class); + Boolean enabled = readValue(mapper, json.get("enabled"), Boolean.class); + + Collection grantedAuthorities = parseSimpleGrantedAuthorities(mapper, json.get("authorities")); + + return OauthUserDetails.builder() + .id(id) + .username(username) + .password(password) + .name(name) + .phone(phone) + .email(email) + .tenantId(tenantId) + .accountNonExpired(accountNonExpired) + .accountNonLocked(accountNonLocked) + .credentialsNonExpired(credentialsNonExpired) + .enabled(enabled) + .authorities(grantedAuthorities) + .build(); + } + + private OAuth2Request parseOAuth2Request(ObjectMapper mapper, JsonNode json) { + if (mapper == null || json == null) { + return null; + } + Map requestParameters = readValue(mapper, json.get("requestParameters"), Collections.unmodifiableMap(new HashMap(0)).getClass()); + String clientId = readString(mapper, json.get("clientId")); + String grantType = readString(mapper, json.get("grantType")); + String redirectUri = readString(mapper, json.get("redirectUri")); + Boolean approved = readValue(mapper, json.get("approved"), Boolean.class); + + Set responseTypes = readValue(mapper, json.get("responseTypes"), Set.class); + String scope1 = requestParameters.get("scope"); + Set scope = StringUtils.hasLength(scope1) ? Set.of(scope1.split(",")) : new HashSet<>(); + Set resourceIds = readValue(mapper, json.get("resourceIds"), Set.class); + Map extensions = readValue(mapper, json.get("extensions"), new TypeReference<>() { + }); + + Collection grantedAuthorities = parseSimpleGrantedAuthorities(mapper, json.get("authorities")); + OAuth2Request request = new OAuth2Request(requestParameters, clientId, + grantedAuthorities, approved, scope, resourceIds, redirectUri, responseTypes, extensions); + TokenRequest tokenRequest = new TokenRequest(requestParameters, clientId, scope, grantType); + request.refresh(tokenRequest); + return request; + } + + /** + * 处理权限 + * + * @param mapper + * @param json + * @return + * @author zhuyijun + * @date 2022/10/15 + */ + private Collection parseSimpleGrantedAuthorities(ObjectMapper mapper, JsonNode json) { + Collection> authorities = readValue(mapper, json, Collection.class); + Collection grantedAuthorities = new ArrayList<>(); + if (authorities != null && !authorities.isEmpty()) { + authorities.forEach(s -> { + if (s != null && !s.isEmpty()) { + grantedAuthorities.add(new SimpleGrantedAuthority(s.get("authority"))); + } + }); + } + return grantedAuthorities; + } + + private JsonNode readJsonNode(JsonNode jsonNode, String field) { + return jsonNode.has(field) ? jsonNode.get(field) : MissingNode.getInstance(); + } + +} diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/redis/serializer/OAuth2AuthenticationMixin.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/redis/serializer/OAuth2AuthenticationMixin.java new file mode 100644 index 0000000..d0093cf --- /dev/null +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/redis/serializer/OAuth2AuthenticationMixin.java @@ -0,0 +1,14 @@ +package cn.zyjblogs.config.redis.serializer; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +/** + * OAuth2Authentication混入类 + * + * @author zhuyijun + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) +@JsonDeserialize(using = OAuth2AuthenticationJackson2Deserializer.class) +public abstract class OAuth2AuthenticationMixin { +} diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/AuthorizationServerConfiguration.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/AuthorizationServerConfiguration.java index bb68be5..81e2212 100644 --- a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/AuthorizationServerConfiguration.java +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/AuthorizationServerConfiguration.java @@ -1,5 +1,7 @@ package cn.zyjblogs.config.security; +import cn.zyjblogs.config.security.policy.OauthAuthorizationCodeServices; +import cn.zyjblogs.starter.redis.utils.RedisTemplateHandler; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -11,8 +13,8 @@ import org.springframework.security.oauth2.config.annotation.web.configuration.E import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; import org.springframework.security.oauth2.provider.ClientDetailsService; +import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService; import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices; -import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices; import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices; import org.springframework.security.oauth2.provider.token.DefaultTokenServices; import org.springframework.security.oauth2.provider.token.TokenEnhancerChain; @@ -39,6 +41,8 @@ public class AuthorizationServerConfiguration extends AuthorizationServerConfigu private final JwtTokenEnhancer jwtTokenEnhancer; private final OauthResponseExceptionTranslator oAuthResponseExceptionTranslator; private final ClientDetailsService oauthClientDetailsService; + private final RedisTemplateHandler redisTemplateHandler; + /** * 令牌端点的安全约束 * @@ -120,15 +124,15 @@ public class AuthorizationServerConfiguration extends AuthorizationServerConfigu @Bean public ClientDetailsService clientDetails(DataSource dataSource) { -// JdbcClientDetailsService jdbcClientDetailsService = new JdbcClientDetailsService(dataSource); -// jdbcClientDetailsService.setPasswordEncoder(passwordEncoder); - return oauthClientDetailsService; + JdbcClientDetailsService jdbcClientDetailsService = new JdbcClientDetailsService(dataSource); + return jdbcClientDetailsService; } @Bean public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource) { //设置授权码模式的授权码如何存取 - return new JdbcAuthorizationCodeServices(dataSource); + return new OauthAuthorizationCodeServices(redisTemplateHandler); +// return new JdbcAuthorizationCodeServices(dataSource); } } \ No newline at end of file diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/OauthAccessTokenConverter.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/OauthAccessTokenConverter.java index 68ddadc..23746fd 100644 --- a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/OauthAccessTokenConverter.java +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/OauthAccessTokenConverter.java @@ -24,7 +24,8 @@ public class OauthAccessTokenConverter extends DefaultAccessTokenConverter { String userId = (String) map.get(ContextKeyConstant.USER_ID_KEY); String username = (String) map.get(ContextKeyConstant.USERNAME_KEY); String tenantId = (String) map.get(ContextKeyConstant.TENANT_ID_KEY); - BaseContext.set(ContextDto.builder().userId(userId).username(username).token(value).tenantId(tenantId).build()); + String name = (String) map.get(ContextKeyConstant.NAME_KEY); + BaseContext.set(ContextDto.builder().userId(userId).username(username).token(value).name(name).tenantId(tenantId).build()); return super.extractAccessToken(value, map); } diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/ResourceServerConfig.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/ResourceServerConfig.java index a5e5b12..5581ef1 100644 --- a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/ResourceServerConfig.java +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/ResourceServerConfig.java @@ -51,14 +51,15 @@ public class ResourceServerConfig extends ResourceServerConfigurerAdapter { .csrf() .disable() //限制资源服务器作用范围为 "/user/**", "/demo/**" - .requestMatchers().antMatchers("/v*/**,/webjars/**", "/swagger-ui.html/**", "/swagger-resources/**", "/v2/api-docs/**", "/v*/user/**", "/demo/**", + .requestMatchers().antMatchers("/v*/**", "/demo/**", String.join(",", whiteListProperties.getAllowPaths())) .and() - .formLogin().and() + .formLogin() + .and() .authorizeRequests() - .antMatchers("/webjars/**", "/swagger-ui.html/**", "/swagger-resources/**", "/v2/api-docs/**", String.join(",", whiteListProperties.getAllowPaths())) + .antMatchers(String.join(",", whiteListProperties.getAllowPaths())) .permitAll() - .antMatchers("/login", "/oauth/**", "/v*/user/login", "/v*/auth/refresh/token").permitAll() + .antMatchers("/v*/user/login", "/v*/auth/refresh/token").permitAll() //以下请求必须认证通过 .anyRequest() .authenticated().and() diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/WebSecurityConfiguration.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/WebSecurityConfiguration.java index 5763d7b..57051ae 100644 --- a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/WebSecurityConfiguration.java +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/WebSecurityConfiguration.java @@ -61,6 +61,7 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { .and() //允许表单登录 .formLogin() +// .loginPage("/login").loginProcessingUrl("/v1/user/login") .and() .httpBasic(); } diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/policy/OauthAuthorizationCodeServices.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/policy/OauthAuthorizationCodeServices.java new file mode 100644 index 0000000..df16845 --- /dev/null +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/policy/OauthAuthorizationCodeServices.java @@ -0,0 +1,54 @@ +package cn.zyjblogs.config.security.policy; + +import cn.zyjblogs.starter.common.entity.constant.CommonRedisKeyConstant; +import cn.zyjblogs.starter.redis.utils.RedisTemplateHandler; +import lombok.SneakyThrows; +import org.springframework.security.oauth2.common.exceptions.InvalidGrantException; +import org.springframework.security.oauth2.common.util.RandomValueStringGenerator; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices; +import org.springframework.security.oauth2.provider.token.store.redis.JdkSerializationStrategy; +import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStoreSerializationStrategy; + +/** + * @author zhuyijun + */ +public class OauthAuthorizationCodeServices implements AuthorizationCodeServices { + private final RedisTemplateHandler redisTemplateHandler; + + public OauthAuthorizationCodeServices(RedisTemplateHandler redisTemplateHandler) { + this.redisTemplateHandler = redisTemplateHandler; + } + + /** + * 生成随机字符的类 + */ + private RandomValueStringGenerator generator = new RandomValueStringGenerator(10); + private RedisTokenStoreSerializationStrategy serializationStrategy = new JdkSerializationStrategy(); + + /** + * @description 生成授权码的方法 + * @param: [oAuth2Authentication] + * @return: java.lang.String + */ + @SneakyThrows + @Override + public String createAuthorizationCode(OAuth2Authentication oAuth2Authentication) { + String code = this.generator.generate(); + redisTemplateHandler.hPut(CommonRedisKeyConstant.AUTHORIZATION_CODE, code, oAuth2Authentication); + return code; + } + + /** + * @description + * @param: [code] + * @return: org.springframework.security.oauth2.provider.OAuth2Authentication + */ + @SneakyThrows + @Override + public OAuth2Authentication consumeAuthorizationCode(String code) throws InvalidGrantException { + return redisTemplateHandler.hGet(CommonRedisKeyConstant.AUTHORIZATION_CODE, code); + } + + +} diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/controller/AuthController.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/controller/AuthController.java index 0aa6937..bbc39c3 100644 --- a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/controller/AuthController.java +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/controller/AuthController.java @@ -44,8 +44,8 @@ public class AuthController { @ApiOperation(value = "获取授权码", notes = "刷新token") @PostMapping("/authorize") @ApiVersion(1) - public void getAuthorizationCode(@RequestBody @Validated AuthorizationCodeDto authorizationCodeDto) { - authService.getAuthorizationCode(authorizationCodeDto); + public ResponseObject getAuthorizationCode(@RequestBody @Validated AuthorizationCodeDto authorizationCodeDto) { + return ResponseResult.success(authService.getAuthorizationCode(authorizationCodeDto)); } } diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/dto/AuthorizationCodeDto.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/dto/AuthorizationCodeDto.java index 8cf147a..86b23eb 100644 --- a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/dto/AuthorizationCodeDto.java +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/dto/AuthorizationCodeDto.java @@ -16,4 +16,9 @@ public class AuthorizationCodeDto { private String clientId; @ApiModelProperty(value = "客户端密码", dataType = "String", example = "all") private String clientSecret; + @ApiModelProperty(value = "返回类型 code token", dataType = "String", example = "all") + private String responseType; + private String state; + private Boolean isApproved; + } diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/dto/AuthorizationDto.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/dto/AuthorizationDto.java new file mode 100644 index 0000000..27e53f9 --- /dev/null +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/dto/AuthorizationDto.java @@ -0,0 +1,101 @@ +package cn.zyjblogs.server.user.dto; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; + +import java.util.Collection; +import java.util.Collections; + +/** + * @author zhuyijun + */ +public class AuthorizationDto implements Authentication { + private String id; + private String name; + private String username; + private Object principal; + private String credentials; + private Collection authorities; + private Object details; + private Boolean authenticated; + + @Override + public Collection getAuthorities() { + return authorities == null ? Collections.emptyList() : authorities; + } + + @Override + public Object getCredentials() { + return credentials; + } + + @Override + public Object getDetails() { + return details; + } + + @Override + public Object getPrincipal() { + return principal; + } + + @Override + public boolean isAuthenticated() { + return authenticated; + } + + @Override + public void setAuthenticated(boolean b) throws IllegalArgumentException { + this.authenticated = b; + } + + @Override + public String getName() { + return name; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public void setName(String name) { + this.name = name; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public void setPrincipal(Object principal) { + this.principal = principal; + } + + public void setCredentials(String credentials) { + this.credentials = credentials; + } + + public void setAuthorities(Collection authorities) { + this.authorities = authorities; + } + + public void setDetails(Object details) { + this.details = details; + } + + public Boolean getAuthenticated() { + return authenticated; + } + + public void setAuthenticated(Boolean authenticated) { + this.authenticated = authenticated; + } +} diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/po/OauthUserDetails.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/po/OauthUserDetails.java index 3c47a69..0df6697 100644 --- a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/po/OauthUserDetails.java +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/po/OauthUserDetails.java @@ -8,6 +8,7 @@ import lombok.Builder; import lombok.NoArgsConstructor; import lombok.Setter; import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import java.io.Serializable; @@ -40,7 +41,7 @@ public class OauthUserDetails implements UserDetails, Serializable { private Integer deleted; private String tenantId; - private Collection authorities; + private Collection authorities; private boolean accountNonExpired = true; private boolean accountNonLocked = true; private boolean credentialsNonExpired = true; @@ -118,7 +119,7 @@ public class OauthUserDetails implements UserDetails, Serializable { this.deleted = deleted; } - public void setAuthorities(Collection authorities) { + public void setAuthorities(Collection authorities) { this.authorities = authorities; } diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/service/AuthService.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/service/AuthService.java index e2849f3..7ff53be 100644 --- a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/service/AuthService.java +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/service/AuthService.java @@ -29,5 +29,5 @@ public interface AuthService { * * @param authorizationCodeDto */ - void getAuthorizationCode(AuthorizationCodeDto authorizationCodeDto); + String getAuthorizationCode(AuthorizationCodeDto authorizationCodeDto); } diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/service/impl/AuthServiceImpl.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/service/impl/AuthServiceImpl.java index 38cd46d..640f85b 100644 --- a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/service/impl/AuthServiceImpl.java +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/service/impl/AuthServiceImpl.java @@ -1,25 +1,52 @@ package cn.zyjblogs.server.user.service.impl; import cn.zyjblogs.server.user.dto.AuthorizationCodeDto; +import cn.zyjblogs.server.user.dto.AuthorizationDto; import cn.zyjblogs.server.user.dto.OAuth2AccessTokenDto; +import cn.zyjblogs.server.user.po.OauthUserDetails; import cn.zyjblogs.server.user.service.AuthService; import cn.zyjblogs.server.user.vo.OAuth2AccessTokenVo; +import cn.zyjblogs.starter.common.entity.context.BaseContext; import cn.zyjblogs.starter.common.entity.response.HttpCode; import cn.zyjblogs.starter.common.exception.AuthRuntimeException; import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.common.exceptions.InvalidRequestException; +import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; +import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException; +import org.springframework.security.oauth2.common.exceptions.UnsupportedResponseTypeException; +import org.springframework.security.oauth2.common.exceptions.UserDeniedAuthorizationException; +import org.springframework.security.oauth2.common.util.OAuth2Utils; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerEndpointsConfiguration; +import org.springframework.security.oauth2.provider.AuthorizationRequest; import org.springframework.security.oauth2.provider.ClientDetails; import org.springframework.security.oauth2.provider.ClientDetailsService; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.security.oauth2.provider.OAuth2Request; import org.springframework.security.oauth2.provider.OAuth2RequestFactory; import org.springframework.security.oauth2.provider.TokenGranter; import org.springframework.security.oauth2.provider.TokenRequest; +import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices; +import org.springframework.security.oauth2.provider.implicit.ImplicitTokenRequest; import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; +import org.springframework.web.util.UriComponents; +import org.springframework.web.util.UriComponentsBuilder; +import java.net.URI; +import java.util.Collections; +import java.util.Date; import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.Map; +import java.util.Set; /** * @author zhuyijun @@ -29,13 +56,18 @@ public class AuthServiceImpl implements AuthService { private final TokenGranter tokenGranter; private final ClientDetailsService clientDetails; private final OAuth2RequestFactory oAuth2RequestFactory; + private final AuthorizationCodeServices authorizationCodeServices; + private final PasswordEncoder passwordEncoder; + private final Object implicitLock = new Object(); public AuthServiceImpl(AuthorizationServerEndpointsConfiguration authorizationServerEndpointsConfiguration, ClientDetailsService clientDetails, - TokenStore tokenStore) { + TokenStore tokenStore, AuthorizationCodeServices authorizationCodeServices, PasswordEncoder passwordEncoder) { this.tokenGranter = authorizationServerEndpointsConfiguration.getEndpointsConfigurer().getTokenGranter(); this.clientDetails = clientDetails; this.oAuth2RequestFactory = new DefaultOAuth2RequestFactory(clientDetails); + this.authorizationCodeServices = authorizationCodeServices; + this.passwordEncoder = passwordEncoder; } @Value("${security.oauth2.client.client-id}") @@ -47,7 +79,7 @@ public class AuthServiceImpl implements AuthService { parameters.put("refresh_token", oAuth2AccessTokenDto.getToken()); parameters.put("grant_type", "refresh_token"); ClientDetails authenticatedClient = clientDetails.loadClientByClientId(clientId); - if (authenticatedClient == null){ + if (authenticatedClient == null) { throw new AuthRuntimeException(HttpCode.INTERNAL_SERVER_ERROR, "客户端获取失败"); } try { @@ -68,19 +100,250 @@ public class AuthServiceImpl implements AuthService { } @Override - public void getAuthorizationCode(AuthorizationCodeDto authorizationCodeDto) { -// Map parameters = new HashMap<>(); -// parameters.put("client_id", authorizationCodeDto.getClientId()); -// parameters.put("client_secret", authorizationCodeDto.getClientSecret()); -// parameters.put("redirect_url", authorizationCodeDto.getRedirectUrl()); -// parameters.put("response_type", "code"); -// parameters.put("scope", authorizationCodeDto.getScope()); -// AuthorizationRequest authorizationRequest = oAuth2RequestFactory.createAuthorizationRequest(parameters); -// try { -// boolean approved = authorizationRequest.isApproved(); -// } catch (Exception e) { -// throw new AuthRuntimeException(HttpCode.INTERNAL_SERVER_ERROR, e.getMessage()); + public String getAuthorizationCode(AuthorizationCodeDto authorizationCodeDto) { + String responseType = authorizationCodeDto.getResponseType(); + if (!StringUtils.hasLength(responseType)) { + throw new AuthRuntimeException(HttpCode.BAD_REQUEST, "responseType不能为空"); + } + Set responseTypes = Set.of(responseType.split(",")); + if (!responseTypes.contains("token") && !responseTypes.contains("code")) { + throw new UnsupportedResponseTypeException("Unsupported response types: " + responseTypes); + } + + ClientDetails clientDetail = this.clientDetails.loadClientByClientId(authorizationCodeDto.getClientId()); + if (clientDetail == null) { + throw new AuthRuntimeException(HttpCode.BAD_REQUEST, "无此客户端"); + } +// if (!passwordEncoder.matches(clientDetail.getClientSecret(), authorizationCodeDto.getClientSecret())) { +// throw new AuthRuntimeException(HttpCode.UNAUTHORIZED, "客户端" + authorizationCodeDto.getClientId() + "认证失败"); // } + Map parameters = new HashMap<>(); + parameters.put(OAuth2Utils.CLIENT_ID, authorizationCodeDto.getClientId()); + parameters.put("client_secret", authorizationCodeDto.getClientSecret()); + parameters.put(OAuth2Utils.REDIRECT_URI, authorizationCodeDto.getRedirectUrl()); + parameters.put(OAuth2Utils.RESPONSE_TYPE, "code"); + parameters.put(OAuth2Utils.SCOPE, authorizationCodeDto.getScope()); + parameters.put(OAuth2Utils.STATE, authorizationCodeDto.getState()); + AuthorizationRequest authorizationRequest = createAuthorizationRequest(parameters, clientDetail); + if (!authorizationCodeDto.getIsApproved()) { + return getUnsuccessfulRedirect(authorizationRequest, + new UserDeniedAuthorizationException("User denied access"), false); + } + if (responseTypes.contains("token")) { + return getImplicitGrantResponse(authorizationRequest); + } + try { + AuthorizationDto authorizationDto = new AuthorizationDto(); + OauthUserDetails oauthUserDetails = new OauthUserDetails(); + oauthUserDetails.setId(BaseContext.getUserId()); + oauthUserDetails.setName(BaseContext.getName()); + oauthUserDetails.setUsername(BaseContext.getUsername()); + oauthUserDetails.setTenantId(BaseContext.getTenantId()); + authorizationDto.setPrincipal(oauthUserDetails); + authorizationDto.setAuthenticated(true); + return getSuccessfulRedirect(authorizationRequest, + generateCode(authorizationRequest, authorizationDto)); + } catch (OAuth2Exception e) { + return getUnsuccessfulRedirect(authorizationRequest, e, false); + } } + /** + * 处理 + * + * @param authorizationParameters + * @param clientDetails + * @return + */ + public AuthorizationRequest createAuthorizationRequest(Map authorizationParameters, ClientDetails clientDetails) { + String clientId = authorizationParameters.get(OAuth2Utils.CLIENT_ID); + String state = authorizationParameters.get(OAuth2Utils.STATE); + String redirectUri = authorizationParameters.get(OAuth2Utils.REDIRECT_URI); + Set responseTypes = OAuth2Utils.parseParameterList(authorizationParameters + .get(OAuth2Utils.RESPONSE_TYPE)); + Set scopes = OAuth2Utils.parseParameterList(authorizationParameters.get(OAuth2Utils.SCOPE)); + if (CollectionUtils.isEmpty(scopes)) { + scopes = clientDetails.getScope(); + } + AuthorizationRequest request = new AuthorizationRequest(authorizationParameters, + Collections.emptyMap(), clientId, scopes, null, null, false, state, redirectUri, + responseTypes); + request.setResourceIdsAndAuthoritiesFromClientDetails(clientDetails); + return request; + + } + + private String appendAccessToken(AuthorizationRequest authorizationRequest, OAuth2AccessToken accessToken) { + + Map vars = new LinkedHashMap(); + Map keys = new HashMap(); + + if (accessToken == null) { + throw new InvalidRequestException("An implicit grant could not be made"); + } + + vars.put("access_token", accessToken.getValue()); + vars.put("refresh_token", accessToken.getRefreshToken()); + vars.put("token_type", accessToken.getTokenType()); + vars.put("expiration", accessToken.getExpiration()); + String state = authorizationRequest.getState(); + + if (state != null) { + vars.put("state", state); + } + Date expiration = accessToken.getExpiration(); + if (expiration != null) { + long expires_in = (expiration.getTime() - System.currentTimeMillis()) / 1000; + vars.put("expires_in", expires_in); + } + String originalScope = authorizationRequest.getRequestParameters().get(OAuth2Utils.SCOPE); + if (originalScope == null || !OAuth2Utils.parseParameterList(originalScope).equals(accessToken.getScope())) { + vars.put("scope", OAuth2Utils.formatParameterList(accessToken.getScope())); + } + Map additionalInformation = accessToken.getAdditionalInformation(); + for (String key : additionalInformation.keySet()) { + Object value = additionalInformation.get(key); + if (value != null) { + keys.put("extra_" + key, key); + vars.put("extra_" + key, value); + } + } + // Do not include the refresh token (even if there is one) + return append(authorizationRequest.getRedirectUri(), vars, keys, true); + } + + private String getImplicitGrantResponse(AuthorizationRequest authorizationRequest) { + try { + TokenRequest tokenRequest = oAuth2RequestFactory.createTokenRequest(authorizationRequest, "implicit"); + OAuth2Request storedOAuth2Request = oAuth2RequestFactory.createOAuth2Request(authorizationRequest); + OAuth2AccessToken accessToken = getAccessTokenForImplicitGrant(tokenRequest, storedOAuth2Request); + if (accessToken == null) { + throw new UnsupportedResponseTypeException("Unsupported response type: token"); + } + return appendAccessToken(authorizationRequest, accessToken); + } catch (OAuth2Exception e) { + return getUnsuccessfulRedirect(authorizationRequest, e, true); + } + } + + private OAuth2AccessToken getAccessTokenForImplicitGrant(TokenRequest tokenRequest, + OAuth2Request storedOAuth2Request) { + OAuth2AccessToken accessToken = null; + // These 1 method calls have to be atomic, otherwise the ImplicitGrantService can have a race condition where + // one thread removes the token request before another has a chance to redeem it. + synchronized (this.implicitLock) { + accessToken = tokenGranter.grant("implicit", + new ImplicitTokenRequest(tokenRequest, storedOAuth2Request)); + } + return accessToken; + } + + private String generateCode(AuthorizationRequest authorizationRequest, Authentication authentication) throws AuthenticationException { + try { + OAuth2Request storedOAuth2Request = this.oAuth2RequestFactory.createOAuth2Request(authorizationRequest); + OAuth2Authentication combinedAuth = new OAuth2Authentication(storedOAuth2Request, authentication); + return this.authorizationCodeServices.createAuthorizationCode(combinedAuth); + } catch (OAuth2Exception e) { + if (authorizationRequest.getState() != null) { + e.addAdditionalInformation("state", authorizationRequest.getState()); + } + throw e; + } + } + + private String append(String base, Map query, Map keys, boolean fragment) { + + UriComponentsBuilder template = UriComponentsBuilder.newInstance(); + UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(base); + URI redirectUri; + try { + // assume it's encoded to start with (if it came in over the wire) + redirectUri = builder.build(true).toUri(); + } catch (Exception e) { + // ... but allow client registrations to contain hard-coded non-encoded values + redirectUri = builder.build().toUri(); + builder = UriComponentsBuilder.fromUri(redirectUri); + } + template.scheme(redirectUri.getScheme()).port(redirectUri.getPort()).host(redirectUri.getHost()) + .userInfo(redirectUri.getUserInfo()).path(redirectUri.getPath()); + + if (fragment) { + StringBuilder values = new StringBuilder(); + if (redirectUri.getFragment() != null) { + String append = redirectUri.getFragment(); + values.append(append); + } + for (String key : query.keySet()) { + if (values.length() > 0) { + values.append("&"); + } + String name = key; + if (keys != null && keys.containsKey(key)) { + name = keys.get(key); + } + values.append(name + "={" + key + "}"); + } + if (values.length() > 0) { + template.fragment(values.toString()); + } + UriComponents encoded = template.build().expand(query).encode(); + builder.fragment(encoded.getFragment()); + } else { + for (String key : query.keySet()) { + String name = key; + if (keys != null && keys.containsKey(key)) { + name = keys.get(key); + } + template.queryParam(name, "{" + key + "}"); + } + template.fragment(redirectUri.getFragment()); + UriComponents encoded = template.build().expand(query).encode(); + builder.query(encoded.getQuery()); + } + + return builder.build().toUriString(); + } + + private String append(String base, Map query, boolean fragment) { + return this.append(base, query, (Map) null, fragment); + } + + private String getSuccessfulRedirect(AuthorizationRequest authorizationRequest, String authorizationCode) { + if (authorizationCode == null) { + throw new IllegalStateException("No authorization code found in the current request scope."); + } else { + Map query = new LinkedHashMap(); + query.put("code", authorizationCode); + String state = authorizationRequest.getState(); + if (state != null) { + query.put("state", state); + } + + return this.append(authorizationRequest.getRedirectUri(), query, false); + } + } + + private String getUnsuccessfulRedirect(AuthorizationRequest authorizationRequest, OAuth2Exception failure, boolean fragment) { + if (authorizationRequest != null && authorizationRequest.getRedirectUri() != null) { + Map query = new LinkedHashMap(); + query.put("error", failure.getOAuth2ErrorCode()); + query.put("error_description", failure.getMessage()); + if (authorizationRequest.getState() != null) { + query.put("state", authorizationRequest.getState()); + } + + if (failure.getAdditionalInformation() != null) { + Iterator var5 = failure.getAdditionalInformation().entrySet().iterator(); + + while (var5.hasNext()) { + Map.Entry additionalInfo = (Map.Entry) var5.next(); + query.put(additionalInfo.getKey(), additionalInfo.getValue()); + } + } + + return this.append(authorizationRequest.getRedirectUri(), query, fragment); + } else { + throw new UnapprovedClientAuthenticationException("Authorization failure, and no redirect URI.", failure); + } + } } diff --git a/stater/zyjblogs-common-spring-boot-starter/pom.xml b/stater/zyjblogs-common-spring-boot-starter/pom.xml index 478caf1..9a12f62 100644 --- a/stater/zyjblogs-common-spring-boot-starter/pom.xml +++ b/stater/zyjblogs-common-spring-boot-starter/pom.xml @@ -17,6 +17,8 @@ 11 11 + + UTF-8 diff --git a/stater/zyjblogs-common-spring-boot-starter/src/main/java/cn/zyjblogs/starter/common/entity/constant/CommonRedisKeyConstant.java b/stater/zyjblogs-common-spring-boot-starter/src/main/java/cn/zyjblogs/starter/common/entity/constant/CommonRedisKeyConstant.java index 99926b5..da8439b 100644 --- a/stater/zyjblogs-common-spring-boot-starter/src/main/java/cn/zyjblogs/starter/common/entity/constant/CommonRedisKeyConstant.java +++ b/stater/zyjblogs-common-spring-boot-starter/src/main/java/cn/zyjblogs/starter/common/entity/constant/CommonRedisKeyConstant.java @@ -4,6 +4,13 @@ package cn.zyjblogs.starter.common.entity.constant; * @author zhuyijun */ public class CommonRedisKeyConstant { + /** + * 授权码 + */ + public final static String AUTHORIZATION_CODE = "OAUTH:AUTHORIZATION_CODE"; + /** + * rsa + */ public static final String REDIS_KEY_PRIVATE_RSA = "rsa:key:private_key"; public static final String REDIS_KEY_PUBLIC_RSA = "rsa:key:public_key"; diff --git a/stater/zyjblogs-common-spring-boot-starter/src/main/java/cn/zyjblogs/starter/common/entity/context/BaseContext.java b/stater/zyjblogs-common-spring-boot-starter/src/main/java/cn/zyjblogs/starter/common/entity/context/BaseContext.java index 72e4661..8332d77 100644 --- a/stater/zyjblogs-common-spring-boot-starter/src/main/java/cn/zyjblogs/starter/common/entity/context/BaseContext.java +++ b/stater/zyjblogs-common-spring-boot-starter/src/main/java/cn/zyjblogs/starter/common/entity/context/BaseContext.java @@ -30,8 +30,13 @@ public class BaseContext { return CONTEXT.get().getUsername(); } + public static String getName() { + return CONTEXT.get().getName(); + } + public static String getTenantId() { - return CONTEXT.get().getTenantId(); + final String tenantId = CONTEXT.get().getTenantId(); + return tenantId == null ? "" : tenantId; } public static String getToken() { diff --git a/stater/zyjblogs-common-spring-boot-starter/src/main/java/cn/zyjblogs/starter/common/entity/dto/ContextDto.java b/stater/zyjblogs-common-spring-boot-starter/src/main/java/cn/zyjblogs/starter/common/entity/dto/ContextDto.java index ca56365..e5c1336 100644 --- a/stater/zyjblogs-common-spring-boot-starter/src/main/java/cn/zyjblogs/starter/common/entity/dto/ContextDto.java +++ b/stater/zyjblogs-common-spring-boot-starter/src/main/java/cn/zyjblogs/starter/common/entity/dto/ContextDto.java @@ -11,6 +11,7 @@ import lombok.NoArgsConstructor; @Builder public class ContextDto { private String userId; + private String name; private String username; private String token; private String tenantId; diff --git a/stater/zyjblogs-feign-spring-boot-starter/pom.xml b/stater/zyjblogs-feign-spring-boot-starter/pom.xml index e63caf2..6b24000 100644 --- a/stater/zyjblogs-feign-spring-boot-starter/pom.xml +++ b/stater/zyjblogs-feign-spring-boot-starter/pom.xml @@ -17,6 +17,8 @@ 11 11 + + UTF-8 diff --git a/stater/zyjblogs-mybatisplus-spring-boot-starter/pom.xml b/stater/zyjblogs-mybatisplus-spring-boot-starter/pom.xml index a94df44..5c23cf7 100644 --- a/stater/zyjblogs-mybatisplus-spring-boot-starter/pom.xml +++ b/stater/zyjblogs-mybatisplus-spring-boot-starter/pom.xml @@ -17,6 +17,8 @@ 11 11 + + UTF-8 diff --git a/stater/zyjblogs-oauth-spring-boot-starter/pom.xml b/stater/zyjblogs-oauth-spring-boot-starter/pom.xml index 997eeac..8dbaa7a 100644 --- a/stater/zyjblogs-oauth-spring-boot-starter/pom.xml +++ b/stater/zyjblogs-oauth-spring-boot-starter/pom.xml @@ -17,6 +17,8 @@ 11 11 + + UTF-8 diff --git a/stater/zyjblogs-oauth-spring-boot-starter/src/main/java/cn/zyjblogs/starter/oauth/token/OauthAccessTokenConverter.java b/stater/zyjblogs-oauth-spring-boot-starter/src/main/java/cn/zyjblogs/starter/oauth/token/OauthAccessTokenConverter.java index cf5ccb3..f55019f 100644 --- a/stater/zyjblogs-oauth-spring-boot-starter/src/main/java/cn/zyjblogs/starter/oauth/token/OauthAccessTokenConverter.java +++ b/stater/zyjblogs-oauth-spring-boot-starter/src/main/java/cn/zyjblogs/starter/oauth/token/OauthAccessTokenConverter.java @@ -3,8 +3,6 @@ package cn.zyjblogs.starter.oauth.token; import cn.zyjblogs.starter.common.entity.constant.ContextKeyConstant; import cn.zyjblogs.starter.common.entity.context.BaseContext; import cn.zyjblogs.starter.common.entity.dto.ContextDto; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.security.oauth2.provider.OAuth2Authentication; import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter; @@ -17,14 +15,14 @@ import java.util.Map; */ @Component public class OauthAccessTokenConverter extends DefaultAccessTokenConverter { - private static final Logger log = LoggerFactory.getLogger(OauthAccessTokenConverter.class); @Override public OAuth2AccessToken extractAccessToken(String value, Map map) { String userId = (String) map.get(ContextKeyConstant.USER_ID_KEY); String username = (String) map.get(ContextKeyConstant.USERNAME_KEY); String tenantId = (String) map.get(ContextKeyConstant.TENANT_ID_KEY); - BaseContext.set(ContextDto.builder().userId(userId).username(username).token(value).tenantId(tenantId).build()); + String name = (String) map.get(ContextKeyConstant.NAME_KEY); + BaseContext.set(ContextDto.builder().userId(userId).username(username).token(value).name(name).tenantId(tenantId).build()); return super.extractAccessToken(value, map); } diff --git a/stater/zyjblogs-rabbitmq-spring-boot-starter/pom.xml b/stater/zyjblogs-rabbitmq-spring-boot-starter/pom.xml index 64f58b0..db0c991 100644 --- a/stater/zyjblogs-rabbitmq-spring-boot-starter/pom.xml +++ b/stater/zyjblogs-rabbitmq-spring-boot-starter/pom.xml @@ -18,6 +18,8 @@ 8 8 + + UTF-8 diff --git a/stater/zyjblogs-redis-spring-boot-starter/pom.xml b/stater/zyjblogs-redis-spring-boot-starter/pom.xml index f27a6ce..69a5a37 100644 --- a/stater/zyjblogs-redis-spring-boot-starter/pom.xml +++ b/stater/zyjblogs-redis-spring-boot-starter/pom.xml @@ -18,6 +18,8 @@ 11 11 + + UTF-8 diff --git a/stater/zyjblogs-redis-spring-boot-starter/src/main/java/cn/zyjblogs/starter/redis/config/GenericJackson2JsonRedisSerializerEx.java b/stater/zyjblogs-redis-spring-boot-starter/src/main/java/cn/zyjblogs/starter/redis/config/GenericJackson2JsonRedisSerializerEx.java index becd910..e38c54b 100644 --- a/stater/zyjblogs-redis-spring-boot-starter/src/main/java/cn/zyjblogs/starter/redis/config/GenericJackson2JsonRedisSerializerEx.java +++ b/stater/zyjblogs-redis-spring-boot-starter/src/main/java/cn/zyjblogs/starter/redis/config/GenericJackson2JsonRedisSerializerEx.java @@ -1,60 +1,64 @@ package cn.zyjblogs.starter.redis.config; - + import com.fasterxml.jackson.annotation.JsonAutoDetect; -import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator; -import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.std.StdSerializer; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.springframework.cache.support.NullValue; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.SerializationException; - + import java.io.IOException; - + /** * @author zhuyijun */ public class GenericJackson2JsonRedisSerializerEx implements RedisSerializer { - + protected GenericJackson2JsonRedisSerializer serializer = null; - + public GenericJackson2JsonRedisSerializerEx() { ObjectMapper om = new ObjectMapper(); - om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.registerModule(new JavaTimeModule()); - this.serializer = new GenericJackson2JsonRedisSerializer(om); + om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + // 反序列化时候遇到不匹配的属性并不抛出异常 忽略json字符串中不识别的属性 + om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + // 序列化时候遇到空对象不抛出异常 忽略无法转换的对象 “No serializer found for class com.xxx.xxx” + om.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + om.setSerializationInclusion(JsonInclude.Include.NON_NULL); + serializer = new GenericJackson2JsonRedisSerializer(om); } - + public GenericJackson2JsonRedisSerializerEx(ObjectMapper om) { this.serializer = new GenericJackson2JsonRedisSerializer(om); } - + @Override public byte[] serialize(Object o) throws SerializationException { return serializer.serialize(o); } - + @Override public Object deserialize(byte[] bytes) throws SerializationException { return serializer.deserialize(bytes); } - - + + protected class NullValueSerializer extends StdSerializer { private static final long serialVersionUID = 1999052150548658807L; - private final String classIdentifier="@class"; - + private final String classIdentifier = "@class"; + NullValueSerializer() { super(NullValue.class); } - + @Override public void serialize(NullValue value, JsonGenerator jgen, SerializerProvider provider) throws IOException { jgen.writeStartObject(); diff --git a/stater/zyjblogs-redis-spring-boot-starter/src/main/java/cn/zyjblogs/starter/redis/config/RedisConfig.java b/stater/zyjblogs-redis-spring-boot-starter/src/main/java/cn/zyjblogs/starter/redis/config/RedisConfiguration.java similarity index 56% rename from stater/zyjblogs-redis-spring-boot-starter/src/main/java/cn/zyjblogs/starter/redis/config/RedisConfig.java rename to stater/zyjblogs-redis-spring-boot-starter/src/main/java/cn/zyjblogs/starter/redis/config/RedisConfiguration.java index b409c81..e81f887 100644 --- a/stater/zyjblogs-redis-spring-boot-starter/src/main/java/cn/zyjblogs/starter/redis/config/RedisConfig.java +++ b/stater/zyjblogs-redis-spring-boot-starter/src/main/java/cn/zyjblogs/starter/redis/config/RedisConfiguration.java @@ -1,12 +1,5 @@ package cn.zyjblogs.starter.redis.config; -import com.fasterxml.jackson.annotation.JsonAutoDetect; -import com.fasterxml.jackson.annotation.PropertyAccessor; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; -import com.fasterxml.jackson.databind.module.SimpleModule; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; @@ -14,37 +7,35 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; /** + * RedisConfig + * * @author zhuyijun */ -@Configuration + +@Configuration( + proxyBeanMethods = false +) @AutoConfigureAfter(RedisAutoConfiguration.class) -public class RedisConfig { +public class RedisConfiguration { /** - * Redis配置 - * 针对key、value、hashKey、hashValue做序列化 - * @return org.springframework.data.redis.core.RedisTemplate + * Redis配置 + * 针对key、value、hashKey、hashValue做序列化 + * + * @return org.springframework.data.redis.core.RedisTemplate */ @Bean @ConditionalOnMissingBean( name = {"redisTemplate"} ) @SuppressWarnings("all") - public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { - RedisTemplate redisTemplate = new RedisTemplate<>(); + public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { + RedisTemplate redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); -// //解决查询缓存转换异常的问题 -// ObjectMapper om = new ObjectMapper(); -// om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); -// //注册java时间处理模块 -// om.registerModule(new JavaTimeModule()); -// GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(om); - GenericJackson2JsonRedisSerializerEx genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializerEx(); //序列号key value @@ -52,7 +43,6 @@ public class RedisConfig { redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer); - redisTemplate.afterPropertiesSet(); return redisTemplate; } diff --git a/stater/zyjblogs-redis-spring-boot-starter/src/main/java/cn/zyjblogs/starter/redis/utils/RedisTemplateHandler.java b/stater/zyjblogs-redis-spring-boot-starter/src/main/java/cn/zyjblogs/starter/redis/utils/RedisTemplateHandler.java index 93ae8f1..25414d3 100644 --- a/stater/zyjblogs-redis-spring-boot-starter/src/main/java/cn/zyjblogs/starter/redis/utils/RedisTemplateHandler.java +++ b/stater/zyjblogs-redis-spring-boot-starter/src/main/java/cn/zyjblogs/starter/redis/utils/RedisTemplateHandler.java @@ -20,54 +20,60 @@ import java.util.concurrent.TimeUnit; @Component @Lazy -public class RedisTemplateHandler { +public class RedisTemplateHandler { @Resource @Lazy - private RedisTemplate redisTemplate; + private RedisTemplate redisTemplate; - public void set(K key,V value){ - redisTemplate.opsForValue().set(key,value); + public void set(K key, V value) { + redisTemplate.opsForValue().set(key, value); } + /** - * @param key 键 - * @param value 值 + * @param key 键 + * @param value 值 * @param l * @param timeUnit - * @author zhuyijun - * @date 2021/12/16 14:33 - * @return void - */ - public void set(K key,V value,long l,TimeUnit timeUnit){ - redisTemplate.opsForValue().set(key,value,l,timeUnit); + * @return void + * @author zhuyijun + * @date 2021/12/16 14:33 + */ + public void set(K key, V value, long l, TimeUnit timeUnit) { + redisTemplate.opsForValue().set(key, value, l, timeUnit); } public V get(K key) { return redisTemplate.opsForValue().get(key); } + /** * 删除key + * * @param key key - * @author zhuyijun - * @date 2021/12/16 15:45 - * @return void - */ + * @return void + * @author zhuyijun + * @date 2021/12/16 15:45 + */ public void delete(K key) { redisTemplate.delete(key); } /** * 通过前缀删除 + * * @param key */ - public void deleteByPrefix(K key){ + public void deleteByPrefix(K key) { Set keys = redisTemplate.keys(key); - if (!CollectionUtils.isEmpty(keys)){ + if (!CollectionUtils.isEmpty(keys)) { redisTemplate.delete(keys); } } + /** * 批量删除key + * * @param keys */ public void delete(Collection keys) { @@ -76,6 +82,7 @@ public class RedisTemplateHandler { /** * 序列化key + * * @param key * @return */ @@ -85,6 +92,7 @@ public class RedisTemplateHandler { /** * 是否存在key + * * @param key * @return */ @@ -166,6 +174,7 @@ public class RedisTemplateHandler { public Long getExpire(K key) { return redisTemplate.getExpire(key); } + /** * 返回 key 所储存的值的类型 * @@ -175,6 +184,7 @@ public class RedisTemplateHandler { public DataType type(K key) { return redisTemplate.type(key); } + /** * 获取存储在哈希表中指定字段的值 * @@ -208,10 +218,10 @@ public class RedisTemplateHandler { return redisTemplate.opsForHash().multiGet(key, fields); } - public boolean hPut(K key, HK hashKey, HV value) { + public boolean hPut(K key, HK hashKey, HV value) { try { if (value != null) { - this.redisTemplate.opsForHash().put(key, hashKey, value); + this.redisTemplate.opsForHash().put(key, hashKey, value); return true; } else { return false; @@ -234,8 +244,8 @@ public class RedisTemplateHandler { * @param value * @return */ - public Boolean hPutIfAbsent(K key, HK hashKey, HV value) { - return redisTemplate.opsForHash().putIfAbsent(key, hashKey, value); + public Boolean hPutIfAbsent(K key, HK hashKey, HV value) { + return redisTemplate.opsForHash().putIfAbsent(key, hashKey, value); } /** @@ -256,8 +266,8 @@ public class RedisTemplateHandler { * @param field * @return */ - public boolean hExists(K key, HV field) { - return redisTemplate.opsForHash().hasKey(key, field); + public boolean hExists(K key, HV field) { + return redisTemplate.opsForHash().hasKey(key, field); } /** @@ -268,8 +278,8 @@ public class RedisTemplateHandler { * @param increment * @return */ - public Long hIncrBy(K key, HK field, long increment) { - return redisTemplate.opsForHash().increment(key, field, increment); + public Long hIncrBy(K key, HK field, long increment) { + return redisTemplate.opsForHash().increment(key, field, increment); } /** @@ -280,8 +290,8 @@ public class RedisTemplateHandler { * @param delta * @return */ - public Double hIncrByFloat(K key, HK field, double delta) { - return redisTemplate.opsForHash().increment(key, field, delta); + public Double hIncrByFloat(K key, HK field, double delta) { + return redisTemplate.opsForHash().increment(key, field, delta); } /** @@ -310,8 +320,8 @@ public class RedisTemplateHandler { * @param key * @return */ - public List hValues(K key) { - return redisTemplate.opsForHash().values(key); + public List hValues(K key) { + return redisTemplate.opsForHash().values(key); } /** @@ -321,8 +331,8 @@ public class RedisTemplateHandler { * @param options * @return */ - public Cursor> hScan(K key, ScanOptions options) { - return redisTemplate.opsForHash().scan(key, options); + public Cursor> hScan(K key, ScanOptions options) { + return redisTemplate.opsForHash().scan(key, options); } /**------------------zSet相关操作--------------------------------*/ @@ -368,6 +378,7 @@ public class RedisTemplateHandler { public Double zIncrementScore(K key, V value, double delta) { return redisTemplate.opsForZSet().incrementScore(key, value, delta); } + /** * 返回元素在集合的排名,有序集合是按照元素的score值由小到大排列 * @@ -411,7 +422,7 @@ public class RedisTemplateHandler { * @return */ public Set> zRangeWithScores(K key, long start, - long end) { + long end) { return redisTemplate.opsForZSet().rangeWithScores(key, start, end); } @@ -436,7 +447,7 @@ public class RedisTemplateHandler { * @return */ public Set> zRangeByScoreWithScores(K key, - double min, double max) { + double min, double max) { return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max); } @@ -449,7 +460,7 @@ public class RedisTemplateHandler { * @return */ public Set> zRangeByScoreWithScores(K key, - double min, double max, long start, long end) { + double min, double max, long start, long end) { return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max, start, end); } @@ -475,7 +486,7 @@ public class RedisTemplateHandler { * @return */ public Set> zReverseRangeWithScores(K key, - long start, long end) { + long start, long end) { return redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end); } @@ -489,7 +500,7 @@ public class RedisTemplateHandler { * @return */ public Set zReverseRangeByScore(K key, double min, - double max) { + double max) { return redisTemplate.opsForZSet().reverseRangeByScore(key, min, max); } @@ -516,7 +527,7 @@ public class RedisTemplateHandler { * @return */ public Set zReverseRangeByScore(K key, double min, - double max, long start, long end) { + double max, long start, long end) { return redisTemplate.opsForZSet().reverseRangeByScore(key, min, max, start, end); } @@ -1116,7 +1127,7 @@ public class RedisTemplateHandler { * @return */ public V lBRightPopAndLeftPush(K sourceKey, K destinationKey, - long timeout, TimeUnit unit) { + long timeout, TimeUnit unit) { return redisTemplate.opsForList().rightPopAndLeftPush(sourceKey, destinationKey, timeout, unit); } diff --git a/stater/zyjblogs-redis-spring-boot-starter/src/main/resources/META-INF/spring.factories b/stater/zyjblogs-redis-spring-boot-starter/src/main/resources/META-INF/spring.factories index f0956bd..b112a4b 100644 --- a/stater/zyjblogs-redis-spring-boot-starter/src/main/resources/META-INF/spring.factories +++ b/stater/zyjblogs-redis-spring-boot-starter/src/main/resources/META-INF/spring.factories @@ -1,3 +1,3 @@ ## Auto Configure org.springframework.boot.cn.zyjblogs.starter.feign.autoconfigure.EnableAutoConfiguration=\ - cn.zyjblogs.starter.redis.config.RedisConfig + cn.zyjblogs.starter.redis.config.RedisConfiguration diff --git a/stater/zyjblogs-web-spring-boot-starter/pom.xml b/stater/zyjblogs-web-spring-boot-starter/pom.xml index 3129c1c..cb0c53f 100644 --- a/stater/zyjblogs-web-spring-boot-starter/pom.xml +++ b/stater/zyjblogs-web-spring-boot-starter/pom.xml @@ -18,6 +18,8 @@ 11 11 + + UTF-8 diff --git a/stater/zyjblogs-web-spring-boot-starter/src/main/java/cn/zyjblogs/starter/web/autoconfig/ApiVersionWebMvcAutoConfiguration.java b/stater/zyjblogs-web-spring-boot-starter/src/main/java/cn/zyjblogs/starter/web/autoconfig/ApiVersionWebMvcAutoConfiguration.java index 76fefd1..8cfff26 100644 --- a/stater/zyjblogs-web-spring-boot-starter/src/main/java/cn/zyjblogs/starter/web/autoconfig/ApiVersionWebMvcAutoConfiguration.java +++ b/stater/zyjblogs-web-spring-boot-starter/src/main/java/cn/zyjblogs/starter/web/autoconfig/ApiVersionWebMvcAutoConfiguration.java @@ -2,8 +2,10 @@ package cn.zyjblogs.starter.web.autoconfig; import cn.zyjblogs.starter.web.apiversion.ApiVersionRequestMappingHandlerMapping; import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; +import org.springframework.web.servlet.view.InternalResourceViewResolver; /** * @author zhuyijun @@ -15,4 +17,9 @@ public class ApiVersionWebMvcAutoConfiguration extends WebMvcConfigurationSuppor public RequestMappingHandlerMapping createRequestMappingHandlerMapping() { return new ApiVersionRequestMappingHandlerMapping(); } + + @Override + protected void configureViewResolvers(ViewResolverRegistry registry) { + registry.viewResolver(new InternalResourceViewResolver()); + } } \ No newline at end of file diff --git a/stater/zyjblogs-web-spring-boot-starter/src/main/java/cn/zyjblogs/starter/web/autoconfig/Knife4jAutoConfigurationConfig.java b/stater/zyjblogs-web-spring-boot-starter/src/main/java/cn/zyjblogs/starter/web/autoconfig/Knife4jAutoConfigurationConfig.java index 2255f94..b310805 100644 --- a/stater/zyjblogs-web-spring-boot-starter/src/main/java/cn/zyjblogs/starter/web/autoconfig/Knife4jAutoConfigurationConfig.java +++ b/stater/zyjblogs-web-spring-boot-starter/src/main/java/cn/zyjblogs/starter/web/autoconfig/Knife4jAutoConfigurationConfig.java @@ -39,39 +39,6 @@ public class Knife4jAutoConfigurationConfig { @Value("${spring.application.name}") private String applicationName; -// @Bean -// public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() { -// return new BeanPostProcessor() { -// -// @Override -// public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { -// if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) { -// customizeSpringfoxHandlerMappings(getHandlerMappings(bean)); -// } -// return bean; -// } -// -// private void customizeSpringfoxHandlerMappings(List mappings) { -// List copy = mappings.stream() -// .filter(mapping -> mapping.getPatternParser() == null) -// .collect(Collectors.toList()); -// mappings.clear(); -// mappings.addAll(copy); -// } -// -// @SuppressWarnings("unchecked") -// private List getHandlerMappings(Object bean) { -// try { -// Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings"); -// field.setAccessible(true); -// return (List) field.get(bean); -// } catch (IllegalArgumentException | IllegalAccessException e) { -// throw new IllegalStateException(e); -// } -// } -// }; -// } - @Bean(value = "defaultApi") public Docket defaultApi() { return new Docket(DocumentationType.SWAGGER_2) @@ -138,4 +105,5 @@ public class Knife4jAutoConfigurationConfig { authorizationScopes[0] = authorizationScope; return Lists.newArrayList(new SecurityReference("BearerToken", authorizationScopes)); } + }