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

Spring新手求助:无需@Autowired填充MyUserPrincipal权限集合

Fixing Null rolesRepository in MyUserPrincipal Without @Autowired

Hey there! I get where you're stuck—since MyUserPrincipal isn't a Spring-managed bean (you didn't annotate it with @Component, @Service, etc.), Spring can't inject dependencies with @Autowired here. Let's go through two solid solutions to populate your GrantedAuthority collection without relying on autowiring.

Solution 1: Pass RolesRepository via Constructor Injection

Since your MyUserPrincipal is typically created by a UserDetailsService (which is a Spring-managed bean), we can inject the repository into the service and pass it directly to MyUserPrincipal's constructor.

Step 1: Update MyUserPrincipal to accept RolesRepository in its constructor

package com.greatproject.dishonline.service;

import com.greatproject.dishonline.entity.Role;
import com.greatproject.dishonline.entity.User;
import com.greatproject.dishonline.repository.RolesRepository;
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.stream.Collectors;

public class MyUserPrincipal implements UserDetails {
    private final User user;
    private final RolesRepository rolesRepository;

    // Constructor with both User and RolesRepository
    public MyUserPrincipal(User user, RolesRepository rolesRepository) {
        this.user = user;
        this.rolesRepository = rolesRepository;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        // Now we can safely use the injected repository
        return rolesRepository.findRolesNames()
                .stream()
                .map(role -> new SimpleGrantedAuthority(role.getName()))
                .collect(Collectors.toList());
    }

    // Remaining UserDetails methods (unchanged)
    @Override
    public String getPassword() {
        return user.getPassword();
    }

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

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

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

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

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

    // Getters/setters if needed
    public User getUser() {
        return user;
    }
}

Step 2: Update your UserDetailsService implementation

Your UserDetailsService is a Spring bean, so it can autowire both UsersRepository and RolesRepository, then pass the repository to MyUserPrincipal:

package com.greatproject.dishonline.service;

import com.greatproject.dishonline.entity.User;
import com.greatproject.dishonline.repository.RolesRepository;
import com.greatproject.dishonline.repository.UsersRepository;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

@Service
public class CustomUserDetailsService implements UserDetailsService {
    private final UsersRepository usersRepository;
    private final RolesRepository rolesRepository;

    // Autowire repositories via constructor (best practice for Spring)
    public CustomUserDetailsService(UsersRepository usersRepository, RolesRepository rolesRepository) {
        this.usersRepository = usersRepository;
        this.rolesRepository = rolesRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = usersRepository.findByLogin(username)
                .orElseThrow(() -> new UsernameNotFoundException("User not found with username: " + username));
        
        // Pass both user and rolesRepository to MyUserPrincipal
        return new MyUserPrincipal(user, rolesRepository);
    }
}

Solution 2: Use Roles Directly from the User Entity (Even Better!)

If your User entity already has a relationship with Role (which it should for a typical Spring Security setup), you can skip the repository entirely and pull roles directly from the user object. This is cleaner and avoids extra database calls.

Step 1: Ensure User entity has a role association

First, check that your User entity is mapped to Role (e.g., a @ManyToMany relationship):

package com.greatproject.dishonline.entity;

import javax.persistence.*;
import java.util.Set;

@Entity
@Table(name = "users")
public class User {
    // Other fields (id, login, password, active, etc.)
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String login;
    private String password;
    private boolean active;

    // Many-to-many relationship with Role (adjust fetch type if needed)
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(
        name = "user_roles",
        joinColumns = @JoinColumn(name = "user_id"),
        inverseJoinColumns = @JoinColumn(name = "role_id")
    )
    private Set<Role> roles;

    // Getters
    public Set<Role> getRoles() {
        return roles;
    }

    // Other getters/setters...
}

Step 2: Update MyUserPrincipal to use roles from the User

Now you can simplify MyUserPrincipal to only take a User in its constructor:

package com.greatproject.dishonline.service;

import com.greatproject.dishonline.entity.Role;
import com.greatproject.dishonline.entity.User;
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.stream.Collectors;

public class MyUserPrincipal implements UserDetails {
    private final User user;

    public MyUserPrincipal(User user) {
        this.user = user;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        // Pull roles directly from the user object
        return user.getRoles()
                .stream()
                .map(role -> new SimpleGrantedAuthority(role.getName()))
                .collect(Collectors.toList());
    }

    // Remaining UserDetails methods (unchanged)
    @Override
    public String getPassword() {
        return user.getPassword();
    }

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

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

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

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

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

    public User getUser() {
        return user;
    }
}

Step 3: Update UserDetailsService (simpler now!)

You no longer need to inject RolesRepository here:

package com.greatproject.dishonline.service;

import com.greatproject.dishonline.entity.User;
import com.greatproject.dishonline.repository.UsersRepository;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

@Service
public class CustomUserDetailsService implements UserDetailsService {
    private final UsersRepository usersRepository;

    public CustomUserDetailsService(UsersRepository usersRepository) {
        this.usersRepository = usersRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = usersRepository.findByLogin(username)
                .orElseThrow(() -> new UsernameNotFoundException("User not found with username: " + username));
        
        // Just pass the user to MyUserPrincipal
        return new MyUserPrincipal(user);
    }
}

Why This Works

The root issue was that MyUserPrincipal isn't managed by Spring, so @Autowired doesn't work. By passing dependencies explicitly (either the repository or using the user's own roles), we avoid relying on Spring's injection for this class.

内容的提问来源于stack exchange,提问作者данил куролесов

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 11:22:33