我无法获得授权,我需要注册

问题描述 投票:0回答:1
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 状态代码显示响应标头的图像

我从过去两天开始尝试,但无法得到它。 我预计问题是什么以及如何解决。

spring spring-boot spring-security
1个回答
0
投票

您有 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();
    }

希望这对您有帮助

© www.soinside.com 2019 - 2024. All rights reserved.