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