解决spring security oauth2 自定义user 用户登录 Jackson报错

自定义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);
Spring Security OAuth2提供了多种方式来进行自定义用户校验。引用中提到了一个关键类DefaultWebResponseExceptionTranslator,它实现了WebResponseExceptionTranslator<OAuth2Exception>接口,用于将异常类统一转换成OAuth2Exception,从而借助HttpMesssageConverters来将OAuth2Exception异常转换成错误响应的格式。这个类可以在异常处理中起到关键作用。 另外,Spring Security OAuth2还提供了AuthenticationManager来处理用户认证。在AuthorizationServerSecurityConfigurer中,可以通过HttpSecurityBuilder.getSharedObject方法获取到AuthenticationManager的实例。但在进行AuthorizationServerConfigurerAdapter的配置时,这个共享对象还未被设定,需要自定义ClientCredentialsTokenEndpointFilter并重写其中的getAuthenticationManager方法来获取AuthenticationManager的实例。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [spring security oauth自定义异常处理(授权服务)](https://blog.csdn.net/qq_43878324/article/details/123142025)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *3* [【Spring Security Oauth2】构建授权服务器(五):自定义用户登录)认证策略](https://blog.csdn.net/apple_csdn/article/details/123389101)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值