【问题标题】:Getting 403 while accessing secured endpoints in SpringBoot even when the roles are matching and user credentials are correct即使角色匹配且用户凭据正确,在 Spring Boot 中访问安全端点时也会出现 403
【发布时间】:2019-01-14 13:25:14
【问题描述】:

下面是安全配置类:-

@EnableWebSecurity
public class SecurityManager extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        super.configure(auth);
    }

    @Bean
    @Override
    public UserDetailsService userDetailsService() {

        UserDetails user=User.builder().username("user").password(passwordEncoder().encode("secret")).
                roles("USER").build();
        UserDetails userAdmin=User.builder().username("admin").password(passwordEncoder().encode("secret")).
                roles("ADMIN").build();
        return new InMemoryUserDetailsManager(user,userAdmin);
    }
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .authorizeRequests()
                .antMatchers("/hello*").hasAnyRole("USER","ADMIN");
    }
}  

下面是我正在访问的控制器:

@RestController
public class DemoController {

    @RequestMapping(value="/helloworld",method= RequestMethod.GET)
    public String sampleGetter()
    {
        return "HelloWorld";
    }

    @RequestMapping(value="/helloinnerclass",method= RequestMethod.GET,produces = MediaType.APPLICATION_JSON_VALUE)
    public InnerClass sampleInnerGetter()
    {
        return new InnerClass("Title","Value");
    }
    class InnerClass
    {
        String title;
        String value;

        public InnerClass(String title, String value) {
            this.title = title;
            this.value = value;
        }

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }
    }

}

通过 Postman 触发上述端点时,我收到 403 状态码。以下是错误截图:-

我没有在项目的属性文件中提到任何与安全性相关的内容,所以我确信基本的安全性没有通过属性文件处理。

【问题讨论】:

  • 请不要在 Stackoverflow 上发布代码截图,只发布格式正确的错误消息本身。

标签: spring-boot authentication spring-security


【解决方案1】:

您是否尝试在您的安全过滤器中启用httpBasic

@Override
protected void configure(HttpSecurity http) throws Exception {
        .csrf().disable()
        .authorizeRequests()
        .antMatchers("/hello*").hasAnyRole("USER","ADMIN")
        .and()
        .httpBasic();
}

我创建了一个完整的sample project,它同时使用了基本登录和表单登录

安全配置与你的类似,但我不希望在实际应用中以明文形式显示密码

@Bean
public PasswordEncoder passwordEncoder(){
    return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}

@Bean
public UserDetailsService userDetailsService() {
    return new InMemoryUserDetailsManager(
        builder()
            .username("user")
            .password("{bcrypt}$2a$10$C8c78G3SRJpy268vInPUFu.3lcNHG9SaNAPdSaIOy.1TJIio0cmTK")
            .roles("USER")
            .build(),
        builder()
            .username("admin")
            .password("{bcrypt}$2a$10$XvWhl0acx2D2hvpOPd/rPuPA48nQGxOFom1NqhxNN9ST1p9lla3bG")
            .roles("ADMIN")
            .build()
    );
}


@Override
protected void configure(HttpSecurity http) throws Exception {
    // @formatter:off
    http
        //application security
        .authorizeRequests()
            .mvcMatchers("/non-secure/**").permitAll()
            .anyRequest().hasAnyRole("ADMIN","USER")
            .and()
        .httpBasic()
            .and()
        .formLogin()
            .and()
    ;
    // @formatter:on
}

我们可以通过simple test 案例证明它有效

@Test
@DisplayName("user / 123 basic authentication")
void userBasic() throws Exception {
    mvc.perform(
        get("/secure")
            .header("Authorization", "Basic " + Base64.encodeBase64String("user:123".getBytes()))
    )
        .andExpect(authenticated())
        .andExpect(status().isOk())
    ;
}

我写了一个simple test 来编码我的密码

@Test
void printPasswords() {
    System.out.println("123 = "+passwordEncoder.encode("123"));
    System.out.println("password = "+passwordEncoder.encode("password"));
}

【讨论】:

  • 在 userDetailsS​​ervice() 方法中,你在 bcrypt 旁边提供的字符串,你从哪里得到这些值?
  • 我已经用test的链接更新了答案
  • 你也可以.password(passwordEncoder().encode("password"))
  • 无法理解 Base64.encodeBase64String("user:123".getBytes())。我的意思是这个字符串 "user:123" 来自哪里?
  • 即http-basic认证protocol,格式为username:password。解释here我已经为你链接了specificationtutorial
猜你喜欢
  • 2015-07-03
  • 2023-03-26
  • 1970-01-01
  • 2019-09-23
  • 1970-01-01
  • 2013-12-15
  • 2014-12-12
  • 2011-01-01
相关资源
最近更新 更多