You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot获取当前认证用户失败,创建Project时遇空指针异常

解决Spring Boot中关联当前认证用户创建Project时的NullPointerException问题

核心问题分析

你的NullPointerException根源有两个:

  1. 请求未携带有效认证信息,导致Authentication或Principal对象为null,调用getName()时触发空指针
  2. 你尝试的(SiteUser) authentication.getPrincipal()强转方式无效,因为UserSecurityService返回的是Spring Security自带的User对象,而非自定义的SiteUser实体

具体解决方案

1. 确保请求携带有效认证凭证

在Postman发送POST请求时,必须携带登录后的认证信息:

  • 若为表单登录:登录后Postman会自动保存Cookie,后续请求直接复用该Cookie即可
  • 若为JWT认证:在请求头中添加Authorization: Bearer <你的JWT Token>
  • 同时给createProject方法添加权限控制,确保未登录用户无法访问:
    @PostMapping
    @PreAuthorize("isAuthenticated()") // 仅允许已登录用户访问
    public Project createProject(...) {
        // ...方法逻辑
    }
    

2. 修改UserSecurityService,返回自定义UserDetails

创建包含SiteUser信息的自定义UserDetails实现,避免重复查询数据库:

package portfolio.backend.api.auth.config;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import portfolio.backend.api.auth.entity.SiteUser;
import java.util.Collection;

public class CustomUserDetails implements UserDetails {
    private final SiteUser siteUser;

    public CustomUserDetails(SiteUser siteUser) {
        this.siteUser = siteUser;
    }

    // 提供获取SiteUser的方法
    public SiteUser getSiteUser() {
        return siteUser;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        // 复用原有的权限逻辑
        return null;
    }

    @Override
    public String getPassword() {
        return siteUser.getPassword();
    }

    @Override
    public String getUsername() {
        return siteUser.getUsername();
    }

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

修改UserSecurityService的loadUserByUsername方法,返回自定义的CustomUserDetails:

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    Optional<SiteUser> _siteUser = this.userRepository.findByUsername(username);
    if (_siteUser.isEmpty()) {
        throw new UsernameNotFoundException("NOT FOUND.");
    }

    SiteUser siteUser = _siteUser.get();
    List<GrantedAuthority> authorities = new ArrayList<>();
    
    if ("admin".equals(username)) {
        authorities.add(new SimpleGrantedAuthority(UserType.ADMIN.getValue()));
    } else {
        authorities.add(new SimpleGrantedAuthority(UserType.USER.getValue()));
    }

    // 返回自定义UserDetails,而非Spring默认的User
    return new CustomUserDetails(siteUser);
}

3. 优化控制器获取当前用户的方式

使用@AuthenticationPrincipal注解直接获取自定义UserDetails,安全拿到用户ID:

import org.springframework.security.core.annotation.AuthenticationPrincipal;
// ...

@PostMapping
@PreAuthorize("isAuthenticated()")
public Project createProject(@AuthenticationPrincipal CustomUserDetails customUserDetails,
                             @RequestParam String projectName) {
    // 直接从CustomUserDetails获取用户ID,无需二次查询数据库
    Long userId = customUserDetails.getSiteUser().getId();

    Project project = new Project();
    project.setUserId(userId);
    project.setProjectName(projectName);
    // ...其他属性设置

    return projectRepository.save(project);
}

额外排查步骤

如果仍出现NPE,按以下方式定位问题:

  1. 查看ProjectController.java第82行代码,确认是authentication/principal为null,还是siteUser为null
  2. 检查Spring Security配置,确认是否正确拦截了Project接口的请求,未登录用户无法访问
  3. 登录成功后打印SecurityContextHolder.getContext().getAuthentication()日志,确认认证信息是否正确存入上下文

内容的提问来源于stack exchange,提问作者user17286087

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 13:34:59