@AuthenticationPrincipal 返回 null

问题描述 投票:0回答:4

我根据参考文档设置了 Spring Security 应用程序,经过数小时的故障排除后,我继续将 null @AuthenticationPrincipal 传递到我的控制器中。

身份验证机制对我数据库中的用户运行良好,但@AuthenticationPrincipal 仍然为空。我查阅了几篇互联网帖子,但仍然无效。

网络安全配置:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    UserService userService;

    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    public DaoAuthenticationProvider provider(){
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setPasswordEncoder(passwordEncoder());
        provider.setUserDetailsService(userService);
        return provider;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                    .authorizeRequests()
                    .antMatchers("/", "/registration").permitAll()
                    .anyRequest().authenticated()
                .and()
                    .formLogin()
                    .loginPage("/login")
                    .permitAll()
                .and()
                    .logout()
                    .permitAll();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(provider());
    }
}

消息(实体):

@Entity
@Table(name = "sweater_message")
public class Message {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String text;

    private String tag;

    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinColumn(name = "user_id")
    private User author;

    public Message(String text, String tag, User user) {
        this.author = user;
        this.text = text;
        this.tag = tag;
    }

    public Message() {
    }
    ...getters and setters

用户(实体):

@Entity
@Table(name = "sweater_user")
public class User implements UserDetails {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String username;

    private String password;

    private boolean active;

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinTable(
            name = "sweater_user_role",
            joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id")
    )
    private Collection<Role> roles;

    public User(String username, String password, boolean active, Collection<Role> roles) {
        this.username = username;
        this.password = password;
        this.active = active;
        this.roles = roles;
    }

    public User() {
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return isActive();
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return getRoles().stream().map(role -> new SimpleGrantedAuthority(role.getName())).collect(Collectors.toList());

   ...getters and setters
    }

用户服务

@Service
public class UserService implements UserDetailsService {
    @Autowired
    private UserRepository userRepository;

    public User save(User user) {
        User saveUser = new User(
                user.getUsername(),
                new BCryptPasswordEncoder().encode(user.getPassword()),
                true,
                Arrays.asList(new Role("USER")));

        return userRepository.save(saveUser);
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User findUser = userRepository.findByUsername(username);

        if (findUser == null) {
            throw new UsernameNotFoundException("There is no user with this username");
        }

        return new org.springframework.security.core.userdetails.User(
                findUser.getUsername(),
                findUser.getPassword(),
                mapRolesToAuthorities(findUser.getRoles()));
    }

    public Collection<? extends GrantedAuthority> mapRolesToAuthorities(Collection<Role> roles) {
        return roles.stream().map(role -> new SimpleGrantedAuthority(role.getName())).collect(Collectors.toSet());
    }
}

控制器:

@PostMapping("/main")
    public String add(
            @AuthenticationPrincipal User user,
            @RequestParam String text,
            @RequestParam String tag,
            Map<String, Object> model
    ){
        ...user is null
    }
spring spring-boot spring-mvc spring-security
4个回答
4
投票

如果您不确定

@AuthenticationPrincipal
应返回什么类型,您可以使用
@AuthenticationPrincipal(errorOnInvalidType=true)
让它抛出异常,如下所示:

@PostMapping("write")
public void write(@AuthenticationPrincipal(errorOnInvalidType=true) String username) {
    ...
}

并检查控制台输出,您应该看到异常并了解主体类型。例如:

java.lang.ClassCastException: org.springframework.security.oauth2.jwt.Jwt@818e7baa is not assignable to class java.lang.String

0
投票

尝试将 @AuthenticationPrincipal User user 更改为 @AuthenticationPrincipal UserDetails userDetails,因为 loadUserByUsername 返回 UserDetails


0
投票

在控制器中使用

SecurityContextHolder.getContext().getAuthentication().getPrincipal()
来查看您的 userdetails 对象是否存储在正确的位置,因为
@AuthenticationPrincipal
(UserDetails)SecurityContextHolder.getContext().getAuthentication().getPrincipal()
的缩写。

例如:

@GetMapping("/all")
public ResponseEntity<String> test(@AuthenticationPrincipal AuthUserDetails userDetails) {
 
    System.out.println(SecurityContextHolder.getContext().getAuthentication().getPrincipal());

    return ResponseEntity.ok("success");

}

如果输出的内容不是

UserDetails
对象,则意味着您在过滤器类中初始化身份验证时没有正确设置
Principal
。我们以
UsernamePasswordAuthenticationToken
为例:

// in filter class

@Component
public class JwtFilter extends OncePerRequestFilter {
    private JwtProvider jwtProvider;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        Optional<AuthUserDetails> authUserDetailOptional = jwtProvider.resolveToken(request); // extract jwt from request, generate a userdetails object

        if (authUserDetailOptional.isPresent()){
            AuthUserDetails authUserDetails = authUserDetailOptional.get();
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                    authUserDetails, // set your authUserDetails here!!
                    null,
                    authUserDetails.getAuthorities()
            ); // generate authentication object

            SecurityContextHolder.getContext().setAuthentication(authentication); 
            filterChain.doFilter(request, response);
        } else {
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "The token is not valid.");

        }

}



0
投票

我使用OAuthentication-ResourceServer并遇到了同样的问题。 我通过创建自己的 RequestPostProcessor 来修复它:

   public static RequestPostProcessor authentication(Authentication authentication) {
        return request -> {
            SecurityContextHolder.getContext().setAuthentication(authentication);
            return request;
        };
    }
© www.soinside.com 2019 - 2024. All rights reserved.