Spring新手求助:无需@Autowired填充MyUserPrincipal权限集合
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,提问作者данил куролесов

