新增授权码模式
This commit is contained in:
parent
bf24b36c62
commit
ed9885bf85
9
pom.xml
9
pom.xml
@ -38,7 +38,6 @@
|
|||||||
<feign-ribbon.version>11.8</feign-ribbon.version>
|
<feign-ribbon.version>11.8</feign-ribbon.version>
|
||||||
<!-- json解析 -->
|
<!-- json解析 -->
|
||||||
<jackson.version>2.13.3</jackson.version>
|
<jackson.version>2.13.3</jackson.version>
|
||||||
<jackson-datatype-jsr310.version>2.13.3</jackson-datatype-jsr310.version>
|
|
||||||
<fastjson.version>2.0.11</fastjson.version>
|
<fastjson.version>2.0.11</fastjson.version>
|
||||||
<!-- ORM -->
|
<!-- ORM -->
|
||||||
<mybatis-plus-boot-starter.version>3.4.3</mybatis-plus-boot-starter.version>
|
<mybatis-plus-boot-starter.version>3.4.3</mybatis-plus-boot-starter.version>
|
||||||
@ -68,7 +67,8 @@
|
|||||||
<commons-crypto.version>1.1.0</commons-crypto.version>
|
<commons-crypto.version>1.1.0</commons-crypto.version>
|
||||||
<!-- 文档-->
|
<!-- 文档-->
|
||||||
<knife4j.version>3.0.3</knife4j.version>
|
<knife4j.version>3.0.3</knife4j.version>
|
||||||
|
<!--编译编码-->
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@ -170,11 +170,6 @@
|
|||||||
<artifactId>nacos-client</artifactId>
|
<artifactId>nacos-client</artifactId>
|
||||||
<version>${nacos-client.version}</version>
|
<version>${nacos-client.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
|
||||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
|
||||||
<version>${jackson-datatype-jsr310.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
|
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba</groupId>
|
<groupId>com.alibaba</groupId>
|
||||||
|
@ -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<java.lang.String, java.lang.Object>
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
public RedisTemplate<Object, Object> 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;
|
||||||
|
}
|
||||||
|
}
|
@ -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<OAuth2AccessToken> {
|
||||||
|
|
||||||
|
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<String, Object> additionalInformation = new LinkedHashMap<String, Object>();
|
||||||
|
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<String> 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;
|
||||||
|
}
|
||||||
|
}
|
@ -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<OAuth2AccessToken> {
|
||||||
|
|
||||||
|
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<String> 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<String, Object> additionalInformation = token.getAdditionalInformation();
|
||||||
|
for (String key : additionalInformation.keySet()) {
|
||||||
|
jgen.writeObjectField(key, additionalInformation.get(key));
|
||||||
|
}
|
||||||
|
jgen.writeEndObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 {
|
||||||
|
}
|
@ -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<OAuth2Authentication> {
|
||||||
|
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> T readValue(ObjectMapper mapper, JsonNode jsonNode, Class<T> 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> T readValue(ObjectMapper mapper, JsonNode jsonNode, TypeReference<T> 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<SimpleGrantedAuthority> 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<SimpleGrantedAuthority> 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<String, String> requestParameters = readValue(mapper, json.get("requestParameters"), Collections.unmodifiableMap(new HashMap<String, String>(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<String> responseTypes = readValue(mapper, json.get("responseTypes"), Set.class);
|
||||||
|
String scope1 = requestParameters.get("scope");
|
||||||
|
Set<String> scope = StringUtils.hasLength(scope1) ? Set.of(scope1.split(",")) : new HashSet<>();
|
||||||
|
Set<String> resourceIds = readValue(mapper, json.get("resourceIds"), Set.class);
|
||||||
|
Map<String, Serializable> extensions = readValue(mapper, json.get("extensions"), new TypeReference<>() {
|
||||||
|
});
|
||||||
|
|
||||||
|
Collection<SimpleGrantedAuthority> 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<SimpleGrantedAuthority> parseSimpleGrantedAuthorities(ObjectMapper mapper, JsonNode json) {
|
||||||
|
Collection<LinkedHashMap<String, String>> authorities = readValue(mapper, json, Collection.class);
|
||||||
|
Collection<SimpleGrantedAuthority> 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 {
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package cn.zyjblogs.config.security;
|
package cn.zyjblogs.config.security;
|
||||||
|
|
||||||
|
import cn.zyjblogs.config.security.policy.OauthAuthorizationCodeServices;
|
||||||
|
import cn.zyjblogs.starter.redis.utils.RedisTemplateHandler;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
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.AuthorizationServerEndpointsConfigurer;
|
||||||
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
|
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
|
||||||
import org.springframework.security.oauth2.provider.ClientDetailsService;
|
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.AuthorizationCodeServices;
|
||||||
import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
|
|
||||||
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
|
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
|
||||||
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
|
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
|
||||||
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
|
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
|
||||||
@ -39,6 +41,8 @@ public class AuthorizationServerConfiguration extends AuthorizationServerConfigu
|
|||||||
private final JwtTokenEnhancer jwtTokenEnhancer;
|
private final JwtTokenEnhancer jwtTokenEnhancer;
|
||||||
private final OauthResponseExceptionTranslator oAuthResponseExceptionTranslator;
|
private final OauthResponseExceptionTranslator oAuthResponseExceptionTranslator;
|
||||||
private final ClientDetailsService oauthClientDetailsService;
|
private final ClientDetailsService oauthClientDetailsService;
|
||||||
|
private final RedisTemplateHandler redisTemplateHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 令牌端点的安全约束
|
* 令牌端点的安全约束
|
||||||
*
|
*
|
||||||
@ -120,15 +124,15 @@ public class AuthorizationServerConfiguration extends AuthorizationServerConfigu
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public ClientDetailsService clientDetails(DataSource dataSource) {
|
public ClientDetailsService clientDetails(DataSource dataSource) {
|
||||||
// JdbcClientDetailsService jdbcClientDetailsService = new JdbcClientDetailsService(dataSource);
|
JdbcClientDetailsService jdbcClientDetailsService = new JdbcClientDetailsService(dataSource);
|
||||||
// jdbcClientDetailsService.setPasswordEncoder(passwordEncoder);
|
return jdbcClientDetailsService;
|
||||||
return oauthClientDetailsService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource) {
|
public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource) {
|
||||||
//设置授权码模式的授权码如何存取
|
//设置授权码模式的授权码如何存取
|
||||||
return new JdbcAuthorizationCodeServices(dataSource);
|
return new OauthAuthorizationCodeServices(redisTemplateHandler);
|
||||||
|
// return new JdbcAuthorizationCodeServices(dataSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -24,7 +24,8 @@ public class OauthAccessTokenConverter extends DefaultAccessTokenConverter {
|
|||||||
String userId = (String) map.get(ContextKeyConstant.USER_ID_KEY);
|
String userId = (String) map.get(ContextKeyConstant.USER_ID_KEY);
|
||||||
String username = (String) map.get(ContextKeyConstant.USERNAME_KEY);
|
String username = (String) map.get(ContextKeyConstant.USERNAME_KEY);
|
||||||
String tenantId = (String) map.get(ContextKeyConstant.TENANT_ID_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);
|
return super.extractAccessToken(value, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,14 +51,15 @@ public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
|
|||||||
.csrf()
|
.csrf()
|
||||||
.disable()
|
.disable()
|
||||||
//限制资源服务器作用范围为 "/user/**", "/demo/**"
|
//限制资源服务器作用范围为 "/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()))
|
String.join(",", whiteListProperties.getAllowPaths()))
|
||||||
.and()
|
.and()
|
||||||
.formLogin().and()
|
.formLogin()
|
||||||
|
.and()
|
||||||
.authorizeRequests()
|
.authorizeRequests()
|
||||||
.antMatchers("/webjars/**", "/swagger-ui.html/**", "/swagger-resources/**", "/v2/api-docs/**", String.join(",", whiteListProperties.getAllowPaths()))
|
.antMatchers(String.join(",", whiteListProperties.getAllowPaths()))
|
||||||
.permitAll()
|
.permitAll()
|
||||||
.antMatchers("/login", "/oauth/**", "/v*/user/login", "/v*/auth/refresh/token").permitAll()
|
.antMatchers("/v*/user/login", "/v*/auth/refresh/token").permitAll()
|
||||||
//以下请求必须认证通过
|
//以下请求必须认证通过
|
||||||
.anyRequest()
|
.anyRequest()
|
||||||
.authenticated().and()
|
.authenticated().and()
|
||||||
|
@ -61,6 +61,7 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
|
|||||||
.and()
|
.and()
|
||||||
//允许表单登录
|
//允许表单登录
|
||||||
.formLogin()
|
.formLogin()
|
||||||
|
// .loginPage("/login").loginProcessingUrl("/v1/user/login")
|
||||||
.and()
|
.and()
|
||||||
.httpBasic();
|
.httpBasic();
|
||||||
}
|
}
|
||||||
|
@ -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<String, OAuth2Authentication> 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.<String, OAuth2Authentication>hGet(CommonRedisKeyConstant.AUTHORIZATION_CODE, code);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -44,8 +44,8 @@ public class AuthController {
|
|||||||
@ApiOperation(value = "获取授权码", notes = "刷新token")
|
@ApiOperation(value = "获取授权码", notes = "刷新token")
|
||||||
@PostMapping("/authorize")
|
@PostMapping("/authorize")
|
||||||
@ApiVersion(1)
|
@ApiVersion(1)
|
||||||
public void getAuthorizationCode(@RequestBody @Validated AuthorizationCodeDto authorizationCodeDto) {
|
public ResponseObject getAuthorizationCode(@RequestBody @Validated AuthorizationCodeDto authorizationCodeDto) {
|
||||||
authService.getAuthorizationCode(authorizationCodeDto);
|
return ResponseResult.success(authService.getAuthorizationCode(authorizationCodeDto));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,4 +16,9 @@ public class AuthorizationCodeDto {
|
|||||||
private String clientId;
|
private String clientId;
|
||||||
@ApiModelProperty(value = "客户端密码", dataType = "String", example = "all")
|
@ApiModelProperty(value = "客户端密码", dataType = "String", example = "all")
|
||||||
private String clientSecret;
|
private String clientSecret;
|
||||||
|
@ApiModelProperty(value = "返回类型 code token", dataType = "String", example = "all")
|
||||||
|
private String responseType;
|
||||||
|
private String state;
|
||||||
|
private Boolean isApproved;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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<SimpleGrantedAuthority> authorities;
|
||||||
|
private Object details;
|
||||||
|
private Boolean authenticated;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<? extends GrantedAuthority> 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<SimpleGrantedAuthority> 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;
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@ import lombok.Builder;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
@ -40,7 +41,7 @@ public class OauthUserDetails implements UserDetails, Serializable {
|
|||||||
|
|
||||||
private Integer deleted;
|
private Integer deleted;
|
||||||
private String tenantId;
|
private String tenantId;
|
||||||
private Collection<Role> authorities;
|
private Collection<SimpleGrantedAuthority> authorities;
|
||||||
private boolean accountNonExpired = true;
|
private boolean accountNonExpired = true;
|
||||||
private boolean accountNonLocked = true;
|
private boolean accountNonLocked = true;
|
||||||
private boolean credentialsNonExpired = true;
|
private boolean credentialsNonExpired = true;
|
||||||
@ -118,7 +119,7 @@ public class OauthUserDetails implements UserDetails, Serializable {
|
|||||||
this.deleted = deleted;
|
this.deleted = deleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAuthorities(Collection<Role> authorities) {
|
public void setAuthorities(Collection<SimpleGrantedAuthority> authorities) {
|
||||||
this.authorities = authorities;
|
this.authorities = authorities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,5 +29,5 @@ public interface AuthService {
|
|||||||
*
|
*
|
||||||
* @param authorizationCodeDto
|
* @param authorizationCodeDto
|
||||||
*/
|
*/
|
||||||
void getAuthorizationCode(AuthorizationCodeDto authorizationCodeDto);
|
String getAuthorizationCode(AuthorizationCodeDto authorizationCodeDto);
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,52 @@
|
|||||||
package cn.zyjblogs.server.user.service.impl;
|
package cn.zyjblogs.server.user.service.impl;
|
||||||
|
|
||||||
import cn.zyjblogs.server.user.dto.AuthorizationCodeDto;
|
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.dto.OAuth2AccessTokenDto;
|
||||||
|
import cn.zyjblogs.server.user.po.OauthUserDetails;
|
||||||
import cn.zyjblogs.server.user.service.AuthService;
|
import cn.zyjblogs.server.user.service.AuthService;
|
||||||
import cn.zyjblogs.server.user.vo.OAuth2AccessTokenVo;
|
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.entity.response.HttpCode;
|
||||||
import cn.zyjblogs.starter.common.exception.AuthRuntimeException;
|
import cn.zyjblogs.starter.common.exception.AuthRuntimeException;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
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.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.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.ClientDetails;
|
||||||
import org.springframework.security.oauth2.provider.ClientDetailsService;
|
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.OAuth2RequestFactory;
|
||||||
import org.springframework.security.oauth2.provider.TokenGranter;
|
import org.springframework.security.oauth2.provider.TokenGranter;
|
||||||
import org.springframework.security.oauth2.provider.TokenRequest;
|
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.request.DefaultOAuth2RequestFactory;
|
||||||
import org.springframework.security.oauth2.provider.token.TokenStore;
|
import org.springframework.security.oauth2.provider.token.TokenStore;
|
||||||
import org.springframework.stereotype.Service;
|
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.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author zhuyijun
|
* @author zhuyijun
|
||||||
@ -29,13 +56,18 @@ public class AuthServiceImpl implements AuthService {
|
|||||||
private final TokenGranter tokenGranter;
|
private final TokenGranter tokenGranter;
|
||||||
private final ClientDetailsService clientDetails;
|
private final ClientDetailsService clientDetails;
|
||||||
private final OAuth2RequestFactory oAuth2RequestFactory;
|
private final OAuth2RequestFactory oAuth2RequestFactory;
|
||||||
|
private final AuthorizationCodeServices authorizationCodeServices;
|
||||||
|
private final PasswordEncoder passwordEncoder;
|
||||||
|
private final Object implicitLock = new Object();
|
||||||
|
|
||||||
public AuthServiceImpl(AuthorizationServerEndpointsConfiguration authorizationServerEndpointsConfiguration,
|
public AuthServiceImpl(AuthorizationServerEndpointsConfiguration authorizationServerEndpointsConfiguration,
|
||||||
ClientDetailsService clientDetails,
|
ClientDetailsService clientDetails,
|
||||||
TokenStore tokenStore) {
|
TokenStore tokenStore, AuthorizationCodeServices authorizationCodeServices, PasswordEncoder passwordEncoder) {
|
||||||
this.tokenGranter = authorizationServerEndpointsConfiguration.getEndpointsConfigurer().getTokenGranter();
|
this.tokenGranter = authorizationServerEndpointsConfiguration.getEndpointsConfigurer().getTokenGranter();
|
||||||
this.clientDetails = clientDetails;
|
this.clientDetails = clientDetails;
|
||||||
this.oAuth2RequestFactory = new DefaultOAuth2RequestFactory(clientDetails);
|
this.oAuth2RequestFactory = new DefaultOAuth2RequestFactory(clientDetails);
|
||||||
|
this.authorizationCodeServices = authorizationCodeServices;
|
||||||
|
this.passwordEncoder = passwordEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Value("${security.oauth2.client.client-id}")
|
@Value("${security.oauth2.client.client-id}")
|
||||||
@ -47,7 +79,7 @@ public class AuthServiceImpl implements AuthService {
|
|||||||
parameters.put("refresh_token", oAuth2AccessTokenDto.getToken());
|
parameters.put("refresh_token", oAuth2AccessTokenDto.getToken());
|
||||||
parameters.put("grant_type", "refresh_token");
|
parameters.put("grant_type", "refresh_token");
|
||||||
ClientDetails authenticatedClient = clientDetails.loadClientByClientId(clientId);
|
ClientDetails authenticatedClient = clientDetails.loadClientByClientId(clientId);
|
||||||
if (authenticatedClient == null){
|
if (authenticatedClient == null) {
|
||||||
throw new AuthRuntimeException(HttpCode.INTERNAL_SERVER_ERROR, "客户端获取失败");
|
throw new AuthRuntimeException(HttpCode.INTERNAL_SERVER_ERROR, "客户端获取失败");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@ -68,19 +100,250 @@ public class AuthServiceImpl implements AuthService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void getAuthorizationCode(AuthorizationCodeDto authorizationCodeDto) {
|
public String getAuthorizationCode(AuthorizationCodeDto authorizationCodeDto) {
|
||||||
// Map<String, String> parameters = new HashMap<>();
|
String responseType = authorizationCodeDto.getResponseType();
|
||||||
// parameters.put("client_id", authorizationCodeDto.getClientId());
|
if (!StringUtils.hasLength(responseType)) {
|
||||||
// parameters.put("client_secret", authorizationCodeDto.getClientSecret());
|
throw new AuthRuntimeException(HttpCode.BAD_REQUEST, "responseType不能为空");
|
||||||
// parameters.put("redirect_url", authorizationCodeDto.getRedirectUrl());
|
}
|
||||||
// parameters.put("response_type", "code");
|
Set<String> responseTypes = Set.of(responseType.split(","));
|
||||||
// parameters.put("scope", authorizationCodeDto.getScope());
|
if (!responseTypes.contains("token") && !responseTypes.contains("code")) {
|
||||||
// AuthorizationRequest authorizationRequest = oAuth2RequestFactory.createAuthorizationRequest(parameters);
|
throw new UnsupportedResponseTypeException("Unsupported response types: " + responseTypes);
|
||||||
// try {
|
}
|
||||||
// boolean approved = authorizationRequest.isApproved();
|
|
||||||
// } catch (Exception e) {
|
ClientDetails clientDetail = this.clientDetails.loadClientByClientId(authorizationCodeDto.getClientId());
|
||||||
// throw new AuthRuntimeException(HttpCode.INTERNAL_SERVER_ERROR, e.getMessage());
|
if (clientDetail == null) {
|
||||||
|
throw new AuthRuntimeException(HttpCode.BAD_REQUEST, "无此客户端");
|
||||||
|
}
|
||||||
|
// if (!passwordEncoder.matches(clientDetail.getClientSecret(), authorizationCodeDto.getClientSecret())) {
|
||||||
|
// throw new AuthRuntimeException(HttpCode.UNAUTHORIZED, "客户端" + authorizationCodeDto.getClientId() + "认证失败");
|
||||||
// }
|
// }
|
||||||
|
Map<String, String> 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<String, String> authorizationParameters, ClientDetails clientDetails) {
|
||||||
|
String clientId = authorizationParameters.get(OAuth2Utils.CLIENT_ID);
|
||||||
|
String state = authorizationParameters.get(OAuth2Utils.STATE);
|
||||||
|
String redirectUri = authorizationParameters.get(OAuth2Utils.REDIRECT_URI);
|
||||||
|
Set<String> responseTypes = OAuth2Utils.parseParameterList(authorizationParameters
|
||||||
|
.get(OAuth2Utils.RESPONSE_TYPE));
|
||||||
|
Set<String> 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<String, Object> vars = new LinkedHashMap<String, Object>();
|
||||||
|
Map<String, String> keys = new HashMap<String, String>();
|
||||||
|
|
||||||
|
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<String, Object> 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<String, ?> query, Map<String, String> 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<String, ?> 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<String, String> 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<String, String> 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<String, String> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>11</maven.compiler.source>
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
<maven.compiler.target>11</maven.compiler.target>
|
<maven.compiler.target>11</maven.compiler.target>
|
||||||
|
<!--编译编码-->
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -4,6 +4,13 @@ package cn.zyjblogs.starter.common.entity.constant;
|
|||||||
* @author zhuyijun
|
* @author zhuyijun
|
||||||
*/
|
*/
|
||||||
public class CommonRedisKeyConstant {
|
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_PRIVATE_RSA = "rsa:key:private_key";
|
||||||
public static final String REDIS_KEY_PUBLIC_RSA = "rsa:key:public_key";
|
public static final String REDIS_KEY_PUBLIC_RSA = "rsa:key:public_key";
|
||||||
|
|
||||||
|
@ -30,8 +30,13 @@ public class BaseContext {
|
|||||||
return CONTEXT.get().getUsername();
|
return CONTEXT.get().getUsername();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getName() {
|
||||||
|
return CONTEXT.get().getName();
|
||||||
|
}
|
||||||
|
|
||||||
public static String getTenantId() {
|
public static String getTenantId() {
|
||||||
return CONTEXT.get().getTenantId();
|
final String tenantId = CONTEXT.get().getTenantId();
|
||||||
|
return tenantId == null ? "" : tenantId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getToken() {
|
public static String getToken() {
|
||||||
|
@ -11,6 +11,7 @@ import lombok.NoArgsConstructor;
|
|||||||
@Builder
|
@Builder
|
||||||
public class ContextDto {
|
public class ContextDto {
|
||||||
private String userId;
|
private String userId;
|
||||||
|
private String name;
|
||||||
private String username;
|
private String username;
|
||||||
private String token;
|
private String token;
|
||||||
private String tenantId;
|
private String tenantId;
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>11</maven.compiler.source>
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
<maven.compiler.target>11</maven.compiler.target>
|
<maven.compiler.target>11</maven.compiler.target>
|
||||||
|
<!--编译编码-->
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<!-- 集成spring-boot自动装配依赖 -->
|
<!-- 集成spring-boot自动装配依赖 -->
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>11</maven.compiler.source>
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
<maven.compiler.target>11</maven.compiler.target>
|
<maven.compiler.target>11</maven.compiler.target>
|
||||||
|
<!--编译编码-->
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<!-- 集成spring-boot自动装配依赖 -->
|
<!-- 集成spring-boot自动装配依赖 -->
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>11</maven.compiler.source>
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
<maven.compiler.target>11</maven.compiler.target>
|
<maven.compiler.target>11</maven.compiler.target>
|
||||||
|
<!--编译编码-->
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -3,8 +3,6 @@ package cn.zyjblogs.starter.oauth.token;
|
|||||||
import cn.zyjblogs.starter.common.entity.constant.ContextKeyConstant;
|
import cn.zyjblogs.starter.common.entity.constant.ContextKeyConstant;
|
||||||
import cn.zyjblogs.starter.common.entity.context.BaseContext;
|
import cn.zyjblogs.starter.common.entity.context.BaseContext;
|
||||||
import cn.zyjblogs.starter.common.entity.dto.ContextDto;
|
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.common.OAuth2AccessToken;
|
||||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||||
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
|
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
|
||||||
@ -17,14 +15,14 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
public class OauthAccessTokenConverter extends DefaultAccessTokenConverter {
|
public class OauthAccessTokenConverter extends DefaultAccessTokenConverter {
|
||||||
private static final Logger log = LoggerFactory.getLogger(OauthAccessTokenConverter.class);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OAuth2AccessToken extractAccessToken(String value, Map<String, ?> map) {
|
public OAuth2AccessToken extractAccessToken(String value, Map<String, ?> map) {
|
||||||
String userId = (String) map.get(ContextKeyConstant.USER_ID_KEY);
|
String userId = (String) map.get(ContextKeyConstant.USER_ID_KEY);
|
||||||
String username = (String) map.get(ContextKeyConstant.USERNAME_KEY);
|
String username = (String) map.get(ContextKeyConstant.USERNAME_KEY);
|
||||||
String tenantId = (String) map.get(ContextKeyConstant.TENANT_ID_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);
|
return super.extractAccessToken(value, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>8</maven.compiler.source>
|
<maven.compiler.source>8</maven.compiler.source>
|
||||||
<maven.compiler.target>8</maven.compiler.target>
|
<maven.compiler.target>8</maven.compiler.target>
|
||||||
|
<!--编译编码-->
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>11</maven.compiler.source>
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
<maven.compiler.target>11</maven.compiler.target>
|
<maven.compiler.target>11</maven.compiler.target>
|
||||||
|
<!--编译编码-->
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<!-- 集成spring-boot自动装配依赖 -->
|
<!-- 集成spring-boot自动装配依赖 -->
|
||||||
|
@ -1,60 +1,64 @@
|
|||||||
package cn.zyjblogs.starter.redis.config;
|
package cn.zyjblogs.starter.redis.config;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
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.annotation.PropertyAccessor;
|
||||||
import com.fasterxml.jackson.core.JsonGenerator;
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
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.databind.ser.std.StdSerializer;
|
||||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||||
import org.springframework.cache.support.NullValue;
|
import org.springframework.cache.support.NullValue;
|
||||||
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
|
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
|
||||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||||
import org.springframework.data.redis.serializer.SerializationException;
|
import org.springframework.data.redis.serializer.SerializationException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author zhuyijun
|
* @author zhuyijun
|
||||||
*/
|
*/
|
||||||
public class GenericJackson2JsonRedisSerializerEx implements RedisSerializer<Object> {
|
public class GenericJackson2JsonRedisSerializerEx implements RedisSerializer<Object> {
|
||||||
|
|
||||||
protected GenericJackson2JsonRedisSerializer serializer = null;
|
protected GenericJackson2JsonRedisSerializer serializer = null;
|
||||||
|
|
||||||
public GenericJackson2JsonRedisSerializerEx() {
|
public GenericJackson2JsonRedisSerializerEx() {
|
||||||
ObjectMapper om = new ObjectMapper();
|
ObjectMapper om = new ObjectMapper();
|
||||||
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
|
||||||
om.registerModule(new JavaTimeModule());
|
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) {
|
public GenericJackson2JsonRedisSerializerEx(ObjectMapper om) {
|
||||||
this.serializer = new GenericJackson2JsonRedisSerializer(om);
|
this.serializer = new GenericJackson2JsonRedisSerializer(om);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] serialize(Object o) throws SerializationException {
|
public byte[] serialize(Object o) throws SerializationException {
|
||||||
return serializer.serialize(o);
|
return serializer.serialize(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object deserialize(byte[] bytes) throws SerializationException {
|
public Object deserialize(byte[] bytes) throws SerializationException {
|
||||||
return serializer.deserialize(bytes);
|
return serializer.deserialize(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected class NullValueSerializer extends StdSerializer<NullValue> {
|
protected class NullValueSerializer extends StdSerializer<NullValue> {
|
||||||
private static final long serialVersionUID = 1999052150548658807L;
|
private static final long serialVersionUID = 1999052150548658807L;
|
||||||
private final String classIdentifier="@class";
|
private final String classIdentifier = "@class";
|
||||||
|
|
||||||
NullValueSerializer() {
|
NullValueSerializer() {
|
||||||
super(NullValue.class);
|
super(NullValue.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void serialize(NullValue value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
|
public void serialize(NullValue value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
|
||||||
jgen.writeStartObject();
|
jgen.writeStartObject();
|
||||||
|
@ -1,12 +1,5 @@
|
|||||||
package cn.zyjblogs.starter.redis.config;
|
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.AutoConfigureAfter;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
|
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.context.annotation.Configuration;
|
||||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
|
|
||||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* RedisConfig
|
||||||
|
*
|
||||||
* @author zhuyijun
|
* @author zhuyijun
|
||||||
*/
|
*/
|
||||||
@Configuration
|
|
||||||
|
@Configuration(
|
||||||
|
proxyBeanMethods = false
|
||||||
|
)
|
||||||
@AutoConfigureAfter(RedisAutoConfiguration.class)
|
@AutoConfigureAfter(RedisAutoConfiguration.class)
|
||||||
public class RedisConfig {
|
public class RedisConfiguration {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Redis配置
|
* Redis配置
|
||||||
* 针对key、value、hashKey、hashValue做序列化
|
* 针对key、value、hashKey、hashValue做序列化
|
||||||
* @return org.springframework.data.redis.core.RedisTemplate<java.lang.String,java.lang.Object>
|
*
|
||||||
|
* @return org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object>
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean(
|
@ConditionalOnMissingBean(
|
||||||
name = {"redisTemplate"}
|
name = {"redisTemplate"}
|
||||||
)
|
)
|
||||||
@SuppressWarnings("all")
|
@SuppressWarnings("all")
|
||||||
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
|
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
|
||||||
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
|
RedisTemplate redisTemplate = new RedisTemplate<>();
|
||||||
redisTemplate.setConnectionFactory(redisConnectionFactory);
|
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();
|
GenericJackson2JsonRedisSerializerEx genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializerEx();
|
||||||
|
|
||||||
//序列号key value
|
//序列号key value
|
||||||
@ -52,7 +43,6 @@ public class RedisConfig {
|
|||||||
redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
|
redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
|
||||||
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
|
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
|
||||||
redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
|
redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
|
||||||
|
|
||||||
redisTemplate.afterPropertiesSet();
|
redisTemplate.afterPropertiesSet();
|
||||||
return redisTemplate;
|
return redisTemplate;
|
||||||
}
|
}
|
@ -20,54 +20,60 @@ import java.util.concurrent.TimeUnit;
|
|||||||
|
|
||||||
@Component
|
@Component
|
||||||
@Lazy
|
@Lazy
|
||||||
public class RedisTemplateHandler<K,V> {
|
public class RedisTemplateHandler<K, V> {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
@Lazy
|
@Lazy
|
||||||
private RedisTemplate<K,V> redisTemplate;
|
private RedisTemplate<K, V> redisTemplate;
|
||||||
|
|
||||||
public void set(K key,V value){
|
public void set(K key, V value) {
|
||||||
redisTemplate.opsForValue().set(key,value);
|
redisTemplate.opsForValue().set(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param key 键
|
* @param key 键
|
||||||
* @param value 值
|
* @param value 值
|
||||||
* @param l
|
* @param l
|
||||||
* @param timeUnit
|
* @param timeUnit
|
||||||
* @author zhuyijun
|
* @return void
|
||||||
* @date 2021/12/16 14:33
|
* @author zhuyijun
|
||||||
* @return void
|
* @date 2021/12/16 14:33
|
||||||
*/
|
*/
|
||||||
public void set(K key,V value,long l,TimeUnit timeUnit){
|
public void set(K key, V value, long l, TimeUnit timeUnit) {
|
||||||
redisTemplate.opsForValue().set(key,value,l,timeUnit);
|
redisTemplate.opsForValue().set(key, value, l, timeUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
public V get(K key) {
|
public V get(K key) {
|
||||||
return redisTemplate.opsForValue().get(key);
|
return redisTemplate.opsForValue().get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除key
|
* 删除key
|
||||||
|
*
|
||||||
* @param key key
|
* @param key key
|
||||||
* @author zhuyijun
|
* @return void
|
||||||
* @date 2021/12/16 15:45
|
* @author zhuyijun
|
||||||
* @return void
|
* @date 2021/12/16 15:45
|
||||||
*/
|
*/
|
||||||
public void delete(K key) {
|
public void delete(K key) {
|
||||||
redisTemplate.delete(key);
|
redisTemplate.delete(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过前缀删除
|
* 通过前缀删除
|
||||||
|
*
|
||||||
* @param key
|
* @param key
|
||||||
*/
|
*/
|
||||||
public void deleteByPrefix(K key){
|
public void deleteByPrefix(K key) {
|
||||||
Set<K> keys = redisTemplate.keys(key);
|
Set<K> keys = redisTemplate.keys(key);
|
||||||
if (!CollectionUtils.isEmpty(keys)){
|
if (!CollectionUtils.isEmpty(keys)) {
|
||||||
redisTemplate.delete(keys);
|
redisTemplate.delete(keys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量删除key
|
* 批量删除key
|
||||||
|
*
|
||||||
* @param keys
|
* @param keys
|
||||||
*/
|
*/
|
||||||
public void delete(Collection<K> keys) {
|
public void delete(Collection<K> keys) {
|
||||||
@ -76,6 +82,7 @@ public class RedisTemplateHandler<K,V> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 序列化key
|
* 序列化key
|
||||||
|
*
|
||||||
* @param key
|
* @param key
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@ -85,6 +92,7 @@ public class RedisTemplateHandler<K,V> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否存在key
|
* 是否存在key
|
||||||
|
*
|
||||||
* @param key
|
* @param key
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@ -166,6 +174,7 @@ public class RedisTemplateHandler<K,V> {
|
|||||||
public Long getExpire(K key) {
|
public Long getExpire(K key) {
|
||||||
return redisTemplate.getExpire(key);
|
return redisTemplate.getExpire(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回 key 所储存的值的类型
|
* 返回 key 所储存的值的类型
|
||||||
*
|
*
|
||||||
@ -175,6 +184,7 @@ public class RedisTemplateHandler<K,V> {
|
|||||||
public DataType type(K key) {
|
public DataType type(K key) {
|
||||||
return redisTemplate.type(key);
|
return redisTemplate.type(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取存储在哈希表中指定字段的值
|
* 获取存储在哈希表中指定字段的值
|
||||||
*
|
*
|
||||||
@ -208,10 +218,10 @@ public class RedisTemplateHandler<K,V> {
|
|||||||
return redisTemplate.<HK, HV>opsForHash().multiGet(key, fields);
|
return redisTemplate.<HK, HV>opsForHash().multiGet(key, fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <HK,HV> boolean hPut(K key, HK hashKey, HV value) {
|
public <HK, HV> boolean hPut(K key, HK hashKey, HV value) {
|
||||||
try {
|
try {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
this.redisTemplate.<HK,HV>opsForHash().put(key, hashKey, value);
|
this.redisTemplate.<HK, HV>opsForHash().put(key, hashKey, value);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@ -234,8 +244,8 @@ public class RedisTemplateHandler<K,V> {
|
|||||||
* @param value
|
* @param value
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public <HK,HV> Boolean hPutIfAbsent(K key, HK hashKey, HV value) {
|
public <HK, HV> Boolean hPutIfAbsent(K key, HK hashKey, HV value) {
|
||||||
return redisTemplate.<HK,HV>opsForHash().putIfAbsent(key, hashKey, value);
|
return redisTemplate.<HK, HV>opsForHash().putIfAbsent(key, hashKey, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -256,8 +266,8 @@ public class RedisTemplateHandler<K,V> {
|
|||||||
* @param field
|
* @param field
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public <HK,HV> boolean hExists(K key, HV field) {
|
public <HK, HV> boolean hExists(K key, HV field) {
|
||||||
return redisTemplate.<HK,HV>opsForHash().hasKey(key, field);
|
return redisTemplate.<HK, HV>opsForHash().hasKey(key, field);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -268,8 +278,8 @@ public class RedisTemplateHandler<K,V> {
|
|||||||
* @param increment
|
* @param increment
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public <HK,HV> Long hIncrBy(K key, HK field, long increment) {
|
public <HK, HV> Long hIncrBy(K key, HK field, long increment) {
|
||||||
return redisTemplate.<HK,HV>opsForHash().increment(key, field, increment);
|
return redisTemplate.<HK, HV>opsForHash().increment(key, field, increment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -280,8 +290,8 @@ public class RedisTemplateHandler<K,V> {
|
|||||||
* @param delta
|
* @param delta
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public <HK,HV> Double hIncrByFloat(K key, HK field, double delta) {
|
public <HK, HV> Double hIncrByFloat(K key, HK field, double delta) {
|
||||||
return redisTemplate.<HK,HV>opsForHash().increment(key, field, delta);
|
return redisTemplate.<HK, HV>opsForHash().increment(key, field, delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -310,8 +320,8 @@ public class RedisTemplateHandler<K,V> {
|
|||||||
* @param key
|
* @param key
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public <HK,HV> List<HV> hValues(K key) {
|
public <HK, HV> List<HV> hValues(K key) {
|
||||||
return redisTemplate.<HK,HV>opsForHash().values(key);
|
return redisTemplate.<HK, HV>opsForHash().values(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -321,8 +331,8 @@ public class RedisTemplateHandler<K,V> {
|
|||||||
* @param options
|
* @param options
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public <HK,HV> Cursor<Map.Entry<HK, HV>> hScan(K key, ScanOptions options) {
|
public <HK, HV> Cursor<Map.Entry<HK, HV>> hScan(K key, ScanOptions options) {
|
||||||
return redisTemplate.<HK,HV>opsForHash().scan(key, options);
|
return redisTemplate.<HK, HV>opsForHash().scan(key, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**------------------zSet相关操作--------------------------------*/
|
/**------------------zSet相关操作--------------------------------*/
|
||||||
@ -368,6 +378,7 @@ public class RedisTemplateHandler<K,V> {
|
|||||||
public Double zIncrementScore(K key, V value, double delta) {
|
public Double zIncrementScore(K key, V value, double delta) {
|
||||||
return redisTemplate.opsForZSet().incrementScore(key, value, delta);
|
return redisTemplate.opsForZSet().incrementScore(key, value, delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回元素在集合的排名,有序集合是按照元素的score值由小到大排列
|
* 返回元素在集合的排名,有序集合是按照元素的score值由小到大排列
|
||||||
*
|
*
|
||||||
@ -411,7 +422,7 @@ public class RedisTemplateHandler<K,V> {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Set<ZSetOperations.TypedTuple<V>> zRangeWithScores(K key, long start,
|
public Set<ZSetOperations.TypedTuple<V>> zRangeWithScores(K key, long start,
|
||||||
long end) {
|
long end) {
|
||||||
return redisTemplate.opsForZSet().rangeWithScores(key, start, end);
|
return redisTemplate.opsForZSet().rangeWithScores(key, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -436,7 +447,7 @@ public class RedisTemplateHandler<K,V> {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Set<ZSetOperations.TypedTuple<V>> zRangeByScoreWithScores(K key,
|
public Set<ZSetOperations.TypedTuple<V>> zRangeByScoreWithScores(K key,
|
||||||
double min, double max) {
|
double min, double max) {
|
||||||
return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max);
|
return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,7 +460,7 @@ public class RedisTemplateHandler<K,V> {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Set<ZSetOperations.TypedTuple<V>> zRangeByScoreWithScores(K key,
|
public Set<ZSetOperations.TypedTuple<V>> 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,
|
return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max,
|
||||||
start, end);
|
start, end);
|
||||||
}
|
}
|
||||||
@ -475,7 +486,7 @@ public class RedisTemplateHandler<K,V> {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Set<ZSetOperations.TypedTuple<V>> zReverseRangeWithScores(K key,
|
public Set<ZSetOperations.TypedTuple<V>> zReverseRangeWithScores(K key,
|
||||||
long start, long end) {
|
long start, long end) {
|
||||||
return redisTemplate.opsForZSet().reverseRangeWithScores(key, start,
|
return redisTemplate.opsForZSet().reverseRangeWithScores(key, start,
|
||||||
end);
|
end);
|
||||||
}
|
}
|
||||||
@ -489,7 +500,7 @@ public class RedisTemplateHandler<K,V> {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Set<V> zReverseRangeByScore(K key, double min,
|
public Set<V> zReverseRangeByScore(K key, double min,
|
||||||
double max) {
|
double max) {
|
||||||
return redisTemplate.opsForZSet().reverseRangeByScore(key, min, max);
|
return redisTemplate.opsForZSet().reverseRangeByScore(key, min, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -516,7 +527,7 @@ public class RedisTemplateHandler<K,V> {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Set<V> zReverseRangeByScore(K key, double min,
|
public Set<V> zReverseRangeByScore(K key, double min,
|
||||||
double max, long start, long end) {
|
double max, long start, long end) {
|
||||||
return redisTemplate.opsForZSet().reverseRangeByScore(key, min, max,
|
return redisTemplate.opsForZSet().reverseRangeByScore(key, min, max,
|
||||||
start, end);
|
start, end);
|
||||||
}
|
}
|
||||||
@ -1116,7 +1127,7 @@ public class RedisTemplateHandler<K,V> {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public V lBRightPopAndLeftPush(K sourceKey, K destinationKey,
|
public V lBRightPopAndLeftPush(K sourceKey, K destinationKey,
|
||||||
long timeout, TimeUnit unit) {
|
long timeout, TimeUnit unit) {
|
||||||
return redisTemplate.opsForList().rightPopAndLeftPush(sourceKey,
|
return redisTemplate.opsForList().rightPopAndLeftPush(sourceKey,
|
||||||
destinationKey, timeout, unit);
|
destinationKey, timeout, unit);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
## Auto Configure
|
## Auto Configure
|
||||||
org.springframework.boot.cn.zyjblogs.starter.feign.autoconfigure.EnableAutoConfiguration=\
|
org.springframework.boot.cn.zyjblogs.starter.feign.autoconfigure.EnableAutoConfiguration=\
|
||||||
cn.zyjblogs.starter.redis.config.RedisConfig
|
cn.zyjblogs.starter.redis.config.RedisConfiguration
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>11</maven.compiler.source>
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
<maven.compiler.target>11</maven.compiler.target>
|
<maven.compiler.target>11</maven.compiler.target>
|
||||||
|
<!--编译编码-->
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<!-- <dependency>-->
|
<!-- <dependency>-->
|
||||||
|
@ -2,8 +2,10 @@ package cn.zyjblogs.starter.web.autoconfig;
|
|||||||
|
|
||||||
import cn.zyjblogs.starter.web.apiversion.ApiVersionRequestMappingHandlerMapping;
|
import cn.zyjblogs.starter.web.apiversion.ApiVersionRequestMappingHandlerMapping;
|
||||||
import org.springframework.context.annotation.Configuration;
|
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.config.annotation.WebMvcConfigurationSupport;
|
||||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||||
|
import org.springframework.web.servlet.view.InternalResourceViewResolver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author zhuyijun
|
* @author zhuyijun
|
||||||
@ -15,4 +17,9 @@ public class ApiVersionWebMvcAutoConfiguration extends WebMvcConfigurationSuppor
|
|||||||
public RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
|
public RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
|
||||||
return new ApiVersionRequestMappingHandlerMapping();
|
return new ApiVersionRequestMappingHandlerMapping();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configureViewResolvers(ViewResolverRegistry registry) {
|
||||||
|
registry.viewResolver(new InternalResourceViewResolver());
|
||||||
|
}
|
||||||
}
|
}
|
@ -39,39 +39,6 @@ public class Knife4jAutoConfigurationConfig {
|
|||||||
@Value("${spring.application.name}")
|
@Value("${spring.application.name}")
|
||||||
private String applicationName;
|
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 <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {
|
|
||||||
// List<T> copy = mappings.stream()
|
|
||||||
// .filter(mapping -> mapping.getPatternParser() == null)
|
|
||||||
// .collect(Collectors.toList());
|
|
||||||
// mappings.clear();
|
|
||||||
// mappings.addAll(copy);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @SuppressWarnings("unchecked")
|
|
||||||
// private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
|
|
||||||
// try {
|
|
||||||
// Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
|
|
||||||
// field.setAccessible(true);
|
|
||||||
// return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
|
|
||||||
// } catch (IllegalArgumentException | IllegalAccessException e) {
|
|
||||||
// throw new IllegalStateException(e);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Bean(value = "defaultApi")
|
@Bean(value = "defaultApi")
|
||||||
public Docket defaultApi() {
|
public Docket defaultApi() {
|
||||||
return new Docket(DocumentationType.SWAGGER_2)
|
return new Docket(DocumentationType.SWAGGER_2)
|
||||||
@ -138,4 +105,5 @@ public class Knife4jAutoConfigurationConfig {
|
|||||||
authorizationScopes[0] = authorizationScope;
|
authorizationScopes[0] = authorizationScope;
|
||||||
return Lists.newArrayList(new SecurityReference("BearerToken", authorizationScopes));
|
return Lists.newArrayList(new SecurityReference("BearerToken", authorizationScopes));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user