token的jackson序列化真是太坑了。。。。。。
目录
ResourceServerConfiguration 资源服务器配置
这个配置的优先级高于WebSecurityConfigurerAdapter,所以HttpSecurity直接在这里配置了,省略WebSecurityConfig
import java.util.Map;
import org.cqg.test.common.util.SpringBeanUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
private Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 处理权限不足
*/
@Autowired
private RequestAccessDeniedHandler requestAccessDeniedHandler;
/**
* 处理 未授权 用户访问 非公有资源
*/
@Autowired
private LoginAuthenticationEntryPoint loginAuthenticationEntryPoint;
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.authenticationEntryPoint(loginAuthenticationEntryPoint)
.accessDeniedHandler(requestAccessDeniedHandler);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/oauth/**").permitAll() // 放行/oauth/token
.antMatchers("/swagger-ui/**", "/swagger-resources/**", "/**/api-docs").permitAll() // 放行swagger
.antMatchers("/favicon.ico").permitAll()//
.antMatchers(HttpMethod.OPTIONS).permitAll()//
.anyRequest().authenticated()//
.and().exceptionHandling()
// 权限不足处理程序 已授权的用户请求权限之外的资源时会交给这个类处理,即自定义403
.accessDeniedHandler(requestAccessDeniedHandler)
// 当一个未授权的用户请求非公有资源时, 这个类的commence方法将会被调用
.authenticationEntryPoint(loginAuthenticationEntryPoint)
// 启用iframe嵌套
// .and().headers().frameOptions().disable()
// 禁用csrf
.and().csrf().disable();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return myAuthenticationManager();
}
@Bean
GrantedAuthorityDefaults grantedAuthorityDefaults() {
return new GrantedAuthorityDefaults(""); // Remove the ROLE_ prefix
}
/**
* 自定义权限管理器,根据不同的client_id调用不同的处理
*
* @return
*/
private MyAuthenticationManager myAuthenticationManager() {
MyAuthenticationManager myAuthenticationManager = new MyAuthenticationManager();
Map<String, Object> beans = SpringBeanUtil.getBeansWithAnnotation(ClientLoginProcessingAnnotation.class);
beans.forEach((name, bean) -> {
ClientLoginProcessingAnnotation anno = bean.getClass().getAnnotation(ClientLoginProcessingAnnotation.class);
if (anno.isDefault()) {
logger.info("默认登录处理器:{} {}", anno.clientId(), anno.info());
myAuthenticationManager.setDefalutProvider((AuthenticationProvider)bean);
} else {
myAuthenticationManager.putProvider(anno.clientId(), (AuthenticationProvider)bean);
}
});
return myAuthenticationManager;
}
}
认证服务器配置
使用jackson序列化oauth2的token,主要在这里实现。自定义一个TokenStore(继承RedisTokenStore),然后替换默认的JdkSerializationStrategy。
import javax.sql.DataSource;
import org.cqg.test.login.oauth2.token.MyRedisTokenStoreService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
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.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.TokenStore;
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private DataSource dataSource;
@Autowired
private RedisConnectionFactory connectionFactory;
@Bean
public TokenStore redisTokenStore() {
MyRedisTokenStoreService tokenStore =
new MyRedisTokenStoreService(jdbcClientDetailsService(), connectionFactory);
return tokenStore;
}
@Bean
public JdbcClientDetailsService jdbcClientDetailsService() {
return new JdbcClientDetailsService(dataSource);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager).tokenStore(redisTokenStore());
}
}
自定义RedisTokenStore
import java.util.Date;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
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.token.store.redis.RedisTokenStore;
public class MyRedisTokenStoreService extends RedisTokenStore {
private ClientDetailsService clientDetailsService;
public MyRedisTokenStoreService(ClientDetailsService clientDetailsService,
RedisConnectionFactory connectionFactory) {
super(connectionFactory);
super.setSerializationStrategy(new JacksonSerializationStrategy());
this.clientDetailsService = clientDetailsService;
// Auto-generated constructor stub
}
@Override
public OAuth2Authentication readAuthentication(OAuth2AccessToken token) {
OAuth2Authentication result = readAuthentication(token.getValue());
if (result != null) {
// 如果token没有失效 更新AccessToken过期时间
DefaultOAuth2AccessToken oAuth2AccessToken = (DefaultOAuth2AccessToken)token;
// 重新设置过期时间
int validitySeconds = getAccessTokenValiditySeconds(result.getOAuth2Request());
if (validitySeconds > 0) {
oAuth2AccessToken.setExpiration(new Date(System.currentTimeMillis() + (validitySeconds * 1000L)));
}
super.removeAccessToken(token);
// 将重新设置过的过期时间重新存入redis, 此时会覆盖redis中原本的过期时间
storeAccessToken(token, result);
}
return result;
}
protected int getAccessTokenValiditySeconds(OAuth2Request clientAuth) {
if (clientDetailsService != null) {
ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
Integer validity = client.getAccessTokenValiditySeconds();
if (validity != null) {
return validity;
}
}
// default 12 hours.
int accessTokenValiditySeconds = 60 * 60 * 12;
return accessTokenValiditySeconds;
}
}
自定义JacksonSerializationStrategy
到这里基本已经完成了,但是OAuth2AccessToken和OAuth2Authentication的实现类没有无参构造器,jackson无法序列化成功,还需要做一些处理
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.TimeZone;
import org.cqg.test.common.jackson.HibernateCollectionMixIn;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.store.redis.StandardStringSerializationStrategy;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
public class JacksonSerializationStrategy extends StandardStringSerializationStrategy {
public RedisSerializer<Object> jackson2JsonRedisSerializer() {
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer =
new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
// 反序列化时候遇到不匹配的属性并不抛出异常 忽略json字符串中不识别的属性
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 序列化时候遇到空对象不抛出异常 忽略无法转换的对象 “No serializer found for class com.xxx.xxx”
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
// PrettyPrinter 格式化输出
// objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
// 指定时区,默认 UTC,而不是 jvm 默认时区
objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8:00"));
// 日期类型处理
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
// 序列化时将Long 转成string输出,js的long有精度错误
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule);
// 序列化时忽略懒加载对象
objectMapper.registerModule(new Hibernate5Module());
// 序列化时将hibernate的持久化集合转换成jdk的集合
objectMapper.addMixIn(Collection.class, HibernateCollectionMixIn.class);
objectMapper.addMixIn(OAuth2AccessToken.class, OAuth2AccessTokenMixIn.class);
objectMapper.addMixIn(OAuth2Authentication.class, OAuth2AuthenticationMixin.class);
// 序列化时将null转换成“”
objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
@Override
public void serialize(Object paramT, JsonGenerator paramJsonGenerator,
SerializerProvider paramSerializerProvider) throws IOException {
// 设置返回null转为 空字符串""
paramJsonGenerator.writeString("");
}
});
// 序列化时添加类型,否则反序列化时会报错,无法转换
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL,
JsonTypeInfo.As.PROPERTY);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
return jackson2JsonRedisSerializer;
}
@Override
@SuppressWarnings("unchecked")
protected <T> T deserializeInternal(byte[] bytes, Class<T> clazz) {
return (T)jackson2JsonRedisSerializer().deserialize(bytes);
}
@Override
protected byte[] serializeInternal(Object object) {
return jackson2JsonRedisSerializer().serialize(object);
}
}
OAuth2AccessToken的序列化与反序列化
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 {}
import java.io.IOException;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
import org.springframework.util.Assert;
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;
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();
}
}
import java.io.IOException;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
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 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;
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;
}
}
OAuth2Authentication的反序列化
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
@JsonDeserialize(using = OAuth2AuthenticationDeserializer.class)
public abstract class OAuth2AuthenticationMixin {}
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
public class OAuth2AuthenticationDeserializer extends JsonDeserializer<OAuth2Authentication> {
Logger logger = LoggerFactory.getLogger(OAuth2AuthenticationDeserializer.class);
@Override
public OAuth2Authentication deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
// TODO Auto-generated method stub
ObjectMapper mapper = (ObjectMapper)jp.getCodec();
JsonNode jsonNode = mapper.readTree(jp);
JsonNode oauth2RequestNode = jsonNode.get("oauth2Request");
JsonNode userAuthenticationNode = jsonNode.get("userAuthentication");
JsonNode detailsNode = jsonNode.get("details");
// Missing type id when trying to resolve subtype of [simple type, class
// org.springframework.security.oauth2.provider.TokenRequest]: missing type id property '@class' (for POJO
// property 'refresh')
ObjectNode object = (ObjectNode)oauth2RequestNode;
object.remove("refresh");
OAuth2Request oAuth2Request = mapper.readValue(object.traverse(mapper), OAuth2Request.class);
Authentication authentication = parseAuthentication(mapper, userAuthenticationNode);
OAuth2Authentication token = new OAuth2Authentication(oAuth2Request, authentication);
Object details = mapper.readValue(detailsNode.traverse(mapper), Object.class);
token.setDetails(details);
return token;
}
private Authentication parseAuthentication(ObjectMapper mapper, JsonNode jsonNode)
throws JsonParseException, JsonMappingException, IOException {
JsonNode principalNode = jsonNode.get("principal");
ObjectNode object = (ObjectNode)principalNode;
object.remove("authorities");
UserDetails principal = mapper.readValue(object.traverse(mapper), new TypeReference<UserDetails>() {});
Object credentials =
mapper.readValue(jsonNode.get("credentials").traverse(mapper), new TypeReference<Object>() {});
Set<SimpleGrantedAuthority> grantedAuthorities =
parseSimpleGrantedAuthorities(mapper, jsonNode.get("authorities"));
Class<? extends Object> requestClass = principal.getClass();
Field officeCodeListField = null;
// 2.1 获取属性字段
try {
officeCodeListField = requestClass.getDeclaredField("authorities");
// 2.3 设置属性值
officeCodeListField.setAccessible(true);
officeCodeListField.set(principal, grantedAuthorities);
} catch (Exception e) {
logger.error("{}", e);
}
return new UsernamePasswordAuthenticationToken(principal, credentials, grantedAuthorities);
}
private Set<SimpleGrantedAuthority> parseSimpleGrantedAuthorities(ObjectMapper mapper, JsonNode jsonNode)
throws JsonParseException, JsonMappingException, IOException {
List<JsonNode> authorities =
mapper.readValue(jsonNode.traverse(mapper), new TypeReference<List<JsonNode>>() {});
Set<SimpleGrantedAuthority> grantedAuthorities = new HashSet<>(0);
if (authorities != null && !authorities.isEmpty()) {
authorities.forEach(s -> {
if (s != null && !s.isEmpty()) {
grantedAuthorities.add(new SimpleGrantedAuthority(s.get("authority").asText()));
}
});
}
return grantedAuthorities;
}
}
自定义登陆接口
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.validation.Valid;
import org.cqg.test.common.data.RetMsg;
import org.cqg.test.common.errorcode.MyException;
import org.cqg.test.common.jackson.JacksonUtil;
import org.cqg.test.login.errorcode.ErrorEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
/**
*
* @Description:TODO(自定义Oauth2获取令牌接口)
* @ClassName:LoginController
* @Date:2021年1月20日 下午3:04:13
* @Author:程启罡
*/
@Api(tags = "登录管理")
@RestController
public class LoginController {
@Autowired
private TokenEndpoint tokenEndpoint;
@ApiOperation(value = "登录")
@RequestMapping(value = "/oauth/token", method = RequestMethod.POST)
public RetMsg<LoginRetDTO> postAccessToken(@RequestHeader(name = "Authorization") String authorization,
@RequestBody @Valid LoginDTO data) throws HttpRequestMethodNotSupportedException {
Map<String, String> parameters = JacksonUtil.bean2map(data);
Authentication principal = SecurityContextHolder.getContext().getAuthentication();
User user = (User)principal.getPrincipal();
parameters.put("client_id", user.getUsername());
OAuth2AccessToken oAuth2AccessToken = tokenEndpoint.postAccessToken(principal, parameters).getBody();
LoginRetDTO token = new LoginRetDTO();
token.setAccess_token(oAuth2AccessToken.getValue());
token.setExpires_in(oAuth2AccessToken.getExpiresIn());
token.setScope(oAuth2AccessToken.getScope().stream().collect(Collectors.joining(",")));
token.setToken_type(oAuth2AccessToken.getTokenType());
return new RetMsg<LoginRetDTO>(ErrorEnum.ER000000, token);
}
@ApiOperation(value = "获取权限")
@RequestMapping(value = "/permission", method = RequestMethod.GET)
public RetMsg<Set<String>> postAccessToken() {
UserDetails authUser =
(UserDetails)Optional.ofNullable(SecurityContextHolder.getContext()).map(e -> e.getAuthentication())
.map(e -> e.getPrincipal()).orElseThrow(() -> new MyException(ErrorEnum.ER02M0002));
Set<String> set =
authUser.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet());
return new RetMsg<Set<String>>(ErrorEnum.ER000000, set);
}
}
文章到此就结束了。另外,没有强迫症的就不必要用jackson去序列化token了,麻烦死了。。。。。
版权声明:本文为qq_33797412原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。