import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.secure.models.User;
public interface UserRepository extends JpaRepository<User,Integer>{
Optional<User> findAppUserByUsername(String username);
}
import com.example.secure.repository.UserRepository;
import com.example.secure.models.User;
import org.springframework.stereotype.Service;
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
private final UserRepository appUserRepository;
public UserDetailsServiceImpl(UserRepository appUserRepository) {
this.appUserRepository = appUserRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = appUserRepository
.findAppUserByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("Not found"));
return org.springframework.security.core.userdetails.User.withUsername(user.getUsername())
.password(user.getPassword())
.roles(user.getAuthority())
.build();
}
}
@Entity
public class User{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String username;
private String password;
private String authority;
//constructors setters and getters
}
import java.util.Collection;
import java.util.List;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
public class UserAdapter implements UserDetails {
private User user;
public UserAdapter(User user){
this.user=user;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return List.of(new SimpleGrantedAuthority(user.getAuthority()));
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.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;
}
}
import com.example.secure.models.User;
import com.example.secure.repository.UserRepository;
@RestController
public class SecurityController {
private final UserRepository repo;
private final PasswordEncoder passwordEncoder;
public SecurityController(UserRepository repo, PasswordEncoder passwordEncoder) {
this.repo = repo;
this.passwordEncoder = passwordEncoder;
}
@PostMapping(path = "/register")
public String register(@RequestBody RegistrationRequest request) {
User user = new User();
System.out.println("Controller started");
user.setUsername(request.username());
user.setPassword(passwordEncoder.encode(request.password()));
user.setAuthority(request.authority());
System.out.println(user.toString());
repo.save(user);
System.out.println("Controller ended");
return "New user successfully registered";
}
@GetMapping(path = "/test")
public String test() {
return "Access to '/test' granted";
}
record RegistrationRequest(String username, String password, String authority) {
}
}
import com.example.secure.service.UserDetailsServiceImpl;
@Configuration
@EnableWebSecurity(debug = true)
public class SecurityConfig {
private UserDetailsServiceImpl userDetailsService;
public SecurityConfig(UserDetailsServiceImpl userDetailsService) {
this.userDetailsService = userDetailsService;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(configurer -> configurer.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers(HttpMethod.GET, "/test").hasAuthority("ROLE_USER")
.requestMatchers(HttpMethod.POST, "/register").permitAll()
.anyRequest().denyAll())
.httpBasic(Customizer.withDefaults())
.userDetailsService(userDetailsService);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
以上是我的项目相关的Spring Security代码,当我尝试使用Postman访问端点时,该代码不起作用。当我从 Postman 调用“est”端点时,会从数据库中获取详细信息,但我无法访问该端点。我收到 401 状态代码,如图所示。来自邮递员的 401 状态代码显示响应标头的图像
我从过去两天开始尝试,但无法得到它。 我预计问题是什么以及如何解决。
您有 UserAdapter 类,但实现不完整。请使用以下 UserAdapter 类。
loadUserByUsername():这个抽象方法将返回 UserDetails 类实例,这就是为什么我们必须使用 UserAdapter 类来实现 UserDetails
public class UserAdapter implements UserDetails {
private String username;
private String password;
private List<GrantedAuthority> authorities;
public UserAdapter(User user){
this.username = user.getUsername();
this.password = user.getPassword();
this.authorities = Stream.of(user.getAuthority().split(",")).map(SimpleGrantedAuthority::new).collect(
Collectors.toList());
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() { return this.authorities; }
@Override
public String getPassword() { return this.password; }
@Override
public String getUsername() { return this.username; }
@Override
public boolean isAccountNonExpired() { return false; }
@Override
public boolean isAccountNonLocked() { return false; }
@Override
public boolean isCredentialsNonExpired() { return false; }
@Override
public boolean isEnabled() { return false; }
}
接下来创建一个单独的类并实现 AuthenticationProvider,因此此实现将帮助提供商管理器识别此客户身份验证
@Component
public class CustomizeAuthProvider implements AuthenticationProvider
{
private final UserDetailsService userDetailsService;
public CustomizeAuthProvider(UserDetailsService userDetailsService)
{
this.userDetailsService = userDetailsService;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
try{
UserDetails userDetails = userDetailsService.loadUserByUsername(authentication.getName());
return new UsernamePasswordAuthenticationToken(userDetails.getUsername(),userDetails.getPassword(),userDetails.getAuthorities());
}catch (UsernameNotFoundException e){
throw new BadCredentialsException("Credentials is invalid");
}
}
@Override
public boolean supports(Class<?> authentication) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
}
替换 UserDetailsServiceImpl 类中的 loadUserByserName 方法
@Override
public UserAdapter loadUserByUsername(String username) throws UsernameNotFoundException {
Optional<User> user = appUserRepository.findAppUserByUsername(username);
return user.map(UserAdapter::new).orElseThrow(()->new UsernameNotFoundException("Not found"));
}
还用以下代码更新 securityConfig 方法
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(auth -> auth
.requestMatchers(HttpMethod.GET, "/test").hasAuthority("ROLE_USER")
.requestMatchers(HttpMethod.POST, "/register").permitAll()
.anyRequest().denyAll())
.httpBasic(Customizer.withDefaults())
//here we are providing customer authentication provider
.authenticationProvider(authenticationProvider)
.userDetailsService(userDetailsService);
return http.build();
}
希望这对您有帮助