【问题标题】:Configuring Springboot security, permitted path(s) not authorised 401配置 Spring Boot 安全性,允许路径未授权 401
【发布时间】:2020-11-20 01:55:39
【问题描述】:

我有一个带有端点的 Springboot REST API

  • /api/quizzesGET
  • /api/quizzes/{id}POST
  • /api/registerPOST
  • / GET 这是一个由 Thymeleaf 控制器类管理的欢迎页面

我的安全类设置如下;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    UserDetailsService userDetailsService;

    /* This sets up the security on specified paths according to role of client */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .httpBasic()
                .and().authorizeRequests()
                .antMatchers("/api/quizzes/**").hasRole("USER")
//                .antMatchers("/api/register/").permitAll() // have tried this, still 401
                .antMatchers("/**").permitAll() // does not permit `/api/register` but does `/` and `h2- 
                                                // console
                .and().headers().frameOptions().disable();
    }

    /* This sets up the user roles by searching the database for a match, so they can access the 
    endpoints configured above */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);

    }

    @Bean
    public PasswordEncoder getPasswordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }
}

现在,当我尝试在 Postman 中访问 /api/register 时,响应为 401 unauthorised。我可以访问/。我知道/**是这个目录和任何子目录的通配符,所以它应该匹配root和/api/registerpermitAll()

编辑:更多信息

  • 注释掉SecurityConfig中的所有代码,我可以访问//api/quizzes/api/quizzes/{id}而不是/api/register,实际上它返回403而不是401,这很有趣。
  • antMatchers("/**").permitAll() ,访问除 /api/register 之外的所有内容,现在响应为 401 ?
  • antMatchers("/**).authenticated() ,一切都返回 401 unauthorized

我想知道,所有/api/quizzes 端点都在QuizController 下,但/api/register 端点在它自己的@RestController 控制器类下。我错过了注释吗?看不到,设置一样。

我知道 Spring 没有查看我的 UserService,因为没有打印 sout 消息。我昨天确实有这个工作,它正在从数据库表中获取User。我不确定发生了什么变化。

这是我的用户服务


@Service
public class UserService implements UserDetailsService {

    @Autowired
    static UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String email) {

        Optional<User> user = userRepository.findByEmail(email);
        System.out.println("loadByUsername called");
        if (user.isPresent()) {
            System.out.println("loadUserByUsername called: user.isPresent() = true");
            return new MyUserDetails(user.get().getEmail(), user.get().getPassword());
        } else {
            throw new UsernameNotFoundException("User: " + email + " not found");
        }
    }

    public static void saveUserToDB(User user) {

        if (user.getPassword().length() < 5) {
            throw new UsernameNotFoundException("password too short.");
        }

        Pattern pattern = Pattern.compile("simon\\.aust@hotmail\\.com");
        Matcher matcher = pattern.matcher(user.getEmail());

        if (!matcher.matches()) {
            throw new UsernameNotFoundException("email not correct format");
        }

        userRepository.save(user);
    }

}

用户存储库

public interface UserRepository extends CrudRepository<User, Long> {

    Optional<User> findByEmail(String email);

}

我的用户详情

public class MyUserDetails implements UserDetails {

    private final String username;
    private final String password;

    public MyUserDetails(String username, String password) {
        this.username = username;
        this.password = password;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"));
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public String getUsername() {
        return username;
    }

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

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

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

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

编辑 2; 通过内存身份验证,我可以使用某些端点进行身份验证,但同样不能/api/register

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
    
        auth.inMemoryAuthentication()
           .passwordEncoder(org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance())
                .withUser("user1")
                .password("password")
                .roles("USER");

}
    

【问题讨论】:

    标签: java spring-boot frameworks authorization


    【解决方案1】:

    试试这个:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .httpBasic()
                .and()
                .authorizeRequests()
                .antMatchers("/api/register/**").permitAll()
                .antMatchers("/api/quizzes/**").authenticated()
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder);
    }
    

    【讨论】:

      【解决方案2】:

      这是一个错误,我为此付出了很多努力。 由于我的天真和忽略了我在哪里处理我的异常,我实际上是在一些 if/else 语句上返回一个带有自定义异常的 HTTP 状态。这让我误以为用户身份验证不起作用,而实际上确实如此。 今日课程:使用断点和调试 :)

      【讨论】:

        猜你喜欢
        • 2020-09-27
        • 2020-04-19
        • 2019-02-01
        • 2021-04-07
        • 1970-01-01
        • 2017-03-14
        • 2015-04-24
        • 2021-01-24
        • 2022-01-21
        相关资源
        最近更新 更多