自定义user 在spring security 登录的时候 出现下面的错误
The class with com.dmg.authserver.entity.MyUserDetails and name of com.dmg.authserver.entity.MyUserDetails is not in the allowlist. If you believe this class is safe to deserialize, please provide an explicit mapping using Jackson annotations or by providing a Mixin. If the serialization is only done by a trusted source, you can also enable default typing. See https://github.com/spring-projects/spring-security/issues/4370 for details
package com.dmg.authserver.config;
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.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.MissingNode;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import java.io.IOException;
import java.util.List;
import java.util.Set;
public class MyUserDeserializer extends JsonDeserializer<User> {
private static final TypeReference<List<SimpleGrantedAuthority>> SIMPLE_GRANTED_AUTHORITY_SET = new TypeReference<List<SimpleGrantedAuthority>>() {
};
@Override
public User deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
ObjectMapper mapper = (ObjectMapper) jp.getCodec();
JsonNode jsonNode = mapper.readTree(jp);
List<? extends GrantedAuthority> authorities = mapper.convertValue(jsonNode.get("authorities"),
SIMPLE_GRANTED_AUTHORITY_SET);
JsonNode passwordNode = readJsonNode(jsonNode, "password");
String username = readJsonNode(jsonNode, "username").asText();
String password = passwordNode.asText("");
boolean enabled = readJsonNode(jsonNode, "enabled").asBoolean();
boolean accountNonExpired = readJsonNode(jsonNode, "accountNonExpired").asBoolean();
boolean credentialsNonExpired = readJsonNode(jsonNode, "credentialsNonExpired").asBoolean();
boolean accountNonLocked = readJsonNode(jsonNode, "accountNonLocked").asBoolean();
User result = new User(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked,
authorities);
if (passwordNode.asText(null) == null) {
result.eraseCredentials();
}
return result;
}
private JsonNode readJsonNode(JsonNode jsonNode, String field) {
return jsonNode.has(field) ? jsonNode.get(field) : MissingNode.getInstance();
}
}
package com.dmg.authserver.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
@JsonDeserialize(using = MyUserDeserializer.class)
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE)
@JsonIgnoreProperties(ignoreUnknown = true)
public interface MyUserMixin {
}
package com.dmg.authserver.config;
import com.dmg.authserver.entity.MyUserDetails;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.lob.DefaultLobHandler;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.jackson2.SecurityJackson2Modules;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationConsentService;
import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.oauth2.server.authorization.jackson2.OAuth2AuthorizationServerJackson2Module;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.UUID;
import java.util.List;
import com.fasterxml.jackson.databind.Module;
//开启web安全 应用在web环境下
// 1: 加载了WebSecurityConfiguration配置类, 配置安全认证策略
// 2: 加载了AuthenticationConfiguration, 配置了认证信息
@Slf4j
@EnableWebSecurity
@Configuration
public class SecurityConfig {
/**
*
* 对应 oauth2_authorization表 授权服务
* @param
* @return
* @throws Exception
*/
@Bean
public OAuth2AuthorizationService auth2AuthorizationService(){
/**
* 解决spring security oauth2 自定义user 用户登录 Jackson报错
* The class with com.dmg.authserver.entity.MyUserDetails and name of
* com.dmg.authserver.entity.MyUserDetails is not in the allowlist.
* If you believe this class is safe to deserialize, please provide an
* explicit mapping using Jackson annotations or by providing a Mixin.
* If the serialization is only done by a trusted source, you can also enable default typing.
* See https://github.com/spring-projects/spring-security/issues/4370 for details
*/
JdbcOAuth2AuthorizationService service = new JdbcOAuth2AuthorizationService(jdbcTemplate,
registeredClientRepository());
JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper authorizationRowMapper =
new JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper(
registeredClientRepository());
authorizationRowMapper.setLobHandler(new DefaultLobHandler());
ObjectMapper objectMapper = new ObjectMapper();
ClassLoader classLoader = JdbcOAuth2AuthorizationService.class.getClassLoader();
List<Module> securityModules = SecurityJackson2Modules.getModules(classLoader);
objectMapper.registerModules(securityModules);
objectMapper.registerModule(new OAuth2AuthorizationServerJackson2Module());
//放入自定义的user类
objectMapper.addMixIn(MyUserDetails.class, MyUserMixin.class);
authorizationRowMapper.setObjectMapper(objectMapper);
service.setAuthorizationRowMapper(authorizationRowMapper);
return service;
}
}
package com.dmg.authserver.entity;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
/**
* UserDetails 用户详细信息接口
*
* @param
* @return
* @throws Exception
*/
@Data
public class MyUserDetails implements UserDetails {
private User user;
private List<SimpleGrantedAuthority> simpleGrantedAuthorityList;
public MyUserDetails(User user,List<SimpleGrantedAuthority> simpleGrantedAuthorityList){
this.user=user;
this.simpleGrantedAuthorityList=simpleGrantedAuthorityList;
}
/**
* 获取所有权限
* @return
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return simpleGrantedAuthorityList;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getAccount();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
//是否启用 true:启用, false:禁用
@Override
public boolean isEnabled() {
return true;
}
/**
* 二次处理权限
* 获取字符串集合的权限
* @return
*/
public List<String>getAuthList(){
//转成list集合
return simpleGrantedAuthorityList.stream().map(x->x.getAuthority()).collect(Collectors.toList());
}
}
核心就是下面的代码,改成自己自定义的user就行了
objectMapper.addMixIn(MyUserDetails.class, MyUserMixin.class);