@AuthenticationPrincipal 返回空用户

Posted

技术标签:

【中文标题】@AuthenticationPrincipal 返回空用户【英文标题】:@AuthenticationPrincipal return empty User 【发布时间】:2017-04-24 07:15:33 【问题描述】:

我有这个控制器,用于保存与当前经过身份验证的用户相关的帖子信息:

@PostMapping("/create")
    public String processPost(
            @CurrentUser User activeUser,
            @ModelAttribute @Valid Post post, 
            Errors errors)
        if(errors.hasErrors())
            return "admin/post/create";
        
        User user2 = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        logger.info("Información del usuario mediate @CurrentUser: " + activeUser.toString());
        logger.info("Información del usuario mediate SecurityContextHolder: " + user2.toString());
        post.setAuthor(activeUser);
        postService.create(post);
        return "redirect:/admin/posts/all";
    

@CurrentUser 定义在这里:

package services.security;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.security.core.annotation.AuthenticationPrincipal;

/**
 *
 * @author sergio
 */
@Target(ElementType.PARAMETER, ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@AuthenticationPrincipal
public @interface CurrentUser 

控制器执行时@AuthenticationPrincipal获取的用户为空,SecurityContextHolder获取的用户包含所有信息:

2016-12-10 19:37:52 INFO  PostController:62 - Información del usuario mediate @CurrentUser: Userid=null, username=null, passwordClear=null, confirmPassword=null, password=null, email=null, enabled=true, fullName=null, posts=[]
2016-12-10 19:37:52 INFO  PostController:63 - Información del usuario mediate SecurityContextHolder: Userid=1, username=sergio11, passwordClear=null, confirmPassword=null, password=$2a$10$LJvYTNacIvqZWDQWjF7xaeheK1MrF.FkXxovb2QgcF2CMudA1mM/., email=sss4esob@gmail.com, enabled=true, fullName=Sergio Sánchez Sánchez, posts=[]

据我了解,使用 @EnableWebSecurity 已经在上下文中启用了 @AuthenticationPrincipal 的解析器参数

我的 Spring 安全配置是这样的:

package config.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import services.security.CustomUserDetailsService;
/**
 *
 * @author sergio
 */
@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = CustomUserDetailsService.class)
public class SecurityConfig extends WebSecurityConfigurerAdapter 

    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private DefaultAuthenticationEventPublisher defaultAuthenticationEventPublisher;

    @Bean
    public PasswordEncoder passwordEncoder() 
        PasswordEncoder encoder = new BCryptPasswordEncoder();
        return encoder;
    

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception 
         auth
            .authenticationEventPublisher(defaultAuthenticationEventPublisher)
            .userDetailsService(userDetailsService)
            .passwordEncoder(passwordEncoder());
    

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http.authorizeRequests()
                .antMatchers("/admin/signup").anonymous()
                .antMatchers("/admin/**").authenticated()
                .anyRequest().permitAll()
                .and()
                .formLogin().loginPage("/admin/login").permitAll()
                .usernameParameter("username").passwordParameter("password")
                .and()
                .logout()
                    .logoutRequestMatcher(new AntPathRequestMatcher("/admin/logout"))
                    .logoutSuccessUrl("/admin/login?logout")
                .and()
                .exceptionHandling().accessDeniedPage("/403")
                .and()
                .csrf();
    

    @Bean
    public DefaultAuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher applicationEventPublisher) 
        return new DefaultAuthenticationEventPublisher(applicationEventPublisher);
    

我正在使用 Spring Security 4.2.0.RELEASE

谢谢:)

【问题讨论】:

【参考方案1】:

错误信息很清楚。您的 CustomerUserDetails 对象听起来是一个实体对象。在其中添加一个默认构造函数:

public class CustomUserDetails extends User implements UserDetails 
//..
   public CustomUserDetails()
//..

【讨论】:

谢谢,我已经尝试过了并出现了这个错误:在组的持续时间内,类 [services.security.CustomUserDetails] 的验证失败。换句话说,JPA Bean 验证失败。 看起来对象是空的,因为所有验证都失败了。【参考方案2】:

此问题是因为 CustomFlashMessagesConfigurer 中的 DelegatingFlashMessagesConfiguration 急切地初始化了 handlerExceptionResolver,这会阻止 AuthenticationPrincipalArgumentResolver 在 Spring MVC 构建 DispatcherServlets 自定义参数解析器之前被注册。

所以我变了:

@Configuration
@EnableWebMvc
@ComponentScan(value =  "controllers", "services", "listeners" )
@Import(value =  ThymeleafConfig.class, i18nConfig.class, CustomFlashMessagesConfigurer.class )
public class WebConfig extends WebMvcConfigurerAdapter

对于这个另一个:

@Configuration
@ComponentScan(value =  "controllers", "services", "listeners" )
@Import(value =  ThymeleafConfig.class, i18nConfig.class, CustomFlashMessagesConfigurer.class )
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter

这样就解决了问题。

【讨论】:

以上是关于@AuthenticationPrincipal 返回空用户的主要内容,如果未能解决你的问题,请参考以下文章

@AuthenticationPrincipal 是如何工作的?

@AuthenticationPrincipal 与 Spring Boot 不工作

@AuthenticationPrincipal 返回空用户

使用 @AuthenticationPrincipal 注入自定义 OidcUser 包装器

使用 EnableWebSecurity 时 AuthenticationPrincipal 为空

AuthenticationPrincipal 返回空的 UserDetails 对象