【问题标题】:Basic auth not working with POST endpoint基本身份验证不适用于 POST 端点
【发布时间】:2021-01-13 07:53:07
【问题描述】:

我已经建立了一个我试图用密码保护的网络服务器。我正在尝试使用 spring boot 设置基本身份验证。这是我目前的配置文件:

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

   @Override
   protected void configure(HttpSecurity http) throws Exception {
      http.authorizeRequests()
         .antMatchers("/", "/v1/occupancy/*")
         .permitAll()
         .anyRequest()
         .authenticated()
         .and()
         .httpBasic();
   }
}

这按预期工作并保护我的 GET 端点之一,允许我进行身份验证。

但是,对于 POST 端点,这不起作用。端点如下所示:

@RequestMapping(path = "/v1/admin/repository")
public class RepositoryOptionsController {

    private final EstablishmentOptionsRepositoryService establishmentOptionsRepositoryService;
    private final SubAreaOptionsRepositoryService subAreaOptionsRepositoryService;
@PostMapping("/establishment/options")
public ResponseEntity<String> postEstablishmentOption(@RequestBody OptionsRequestDto body) {

当我这样做时

curl -X POST "http://localhost:8080/v1/admin/repository/establishment/options" -u root -v -d "{...}"

我明白了

    Enter host password for user 'root':
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
* Server auth using Basic with user 'root'
> POST /v1/admin/repository/establishment/options HTTP/1.1
> Host: localhost:8080
> Authorization: Basic cm9vdDpyb290
> User-Agent: curl/7.64.1
> Accept: */*
> Content-Length: 271
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 271 out of 271 bytes
< HTTP/1.1 401
< Set-Cookie: JSESSIONID=6E1CBD875597C83E6DEB794986050631; Path=/; HttpOnly
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
* Authentication problem. Ignoring this.
< WWW-Authenticate: Basic realm="Realm"
< Content-Length: 0
< Date: Sun, 27 Sep 2020 15:29:13 GMT
<
* Connection #0 to host localhost left intact
* Closing connection 0

相同的用户/密码组合在 GET 上正常工作。做什么?

【问题讨论】:

    标签: spring-boot http spring-security basic-authentication


    【解决方案1】:

    配置需要更多步骤。

    1. 配置字符串安全

      @配置 @EnableWebSecurity @EnableTransactionManagement 公共类 SecurityConfiguration 扩展 WebSecurityConfigurerAdapter {

       @Autowired
       private UserDetailServiceImpl userService;
      
       @Autowired
       public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception{
           auth.userDetailsService(userService);
       }
      
      
      
      
       @Override
       protected void configure(HttpSecurity http) throws Exception {
      
           http.authorizeRequests()
                   .antMatchers("/webjars/**", "/styles/**",  "/vendors/**", "/node_modules/**",  "/app/**", 
                           "/assets/**", "/api/channel/**", "/jobs/**").permitAll()
                   .anyRequest().authenticated()
               .and()
                   .formLogin().loginPage("/login").permitAll()
               .and()
                   .logout().logoutSuccessUrl("/login?logout").permitAll()
               .and()
                   .csrf().disable();
       }
      

      }

    2. 实现 UserDetailsS​​ervice @服务 公共类 UserDetailServiceImpl 实现 UserDetailsS​​ervice{ @自动连线 utentiRepository utentiRepository;

       @Override
       public UserDetails loadUserByUsername(String nomeUtente) throws UsernameNotFoundException {
           try {
      
               String userId = nomeUtente;
      
               Utente utente = utentiRepository.findById(userId).get();
      
               UserDetailsImp user = new UserDetailsImp(utente);
               user.username = nomeUtente;
      
               user.password = utente.getPasswd();
      
               return user;
           } catch (Exception e) {
               throw new UsernameNotFoundException(nomeUtente);
           }
       }
      

      } 您在 Spring Security 配置中引用的此服务包含生成实现 UserDetails 接口的对象的所有角色

    3. 实现UserDetails接口

      公共类 UserDetailsImp 实现 UserDetails{

       /**
        * 
        */
       private static final long serialVersionUID = 1L;
       String password;
       String username;
       public Utente utente;
      
       public UserDetailsImp(Utente utente) {
           this.utente = utente;
       }
      
       @Override
       public Collection<? extends GrantedAuthority> getAuthorities() {
           List<GrantedAuthority> res = new ArrayList<>();
           res.add(new SimpleGrantedAuthority("ROLE_MENU"));
           return res;
       }
      
       public String getPassword() {
           return password;
       }
      
       public void setPassword(String password) {
           this.password = password;
       }
      
       public String getUsername() {
           return username;
       }
      
       public void setUsername(String username) {
           this.username = 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;
       }
      
       public String getDenominazione() {
           return utente.getDenominazione();
       }
      
      
      
       public Utente getUtente() {
           return utente;
       }
      
       public void setUtente(Utente utente) {
           this.utente = utente;
       }
      

      }

    就我而言 @自动连线 UtentiRepository utentiRepository; 是一个从用户数据库读取数据的存储库,但您可以使用任何您喜欢的机制。现在 Spring 安全设置好了。

    那你需要在登录页面添加一个表单

    <form class="form-horizontal" id="loginForm" th:action="@{/login}" method="post">
        <input type="text" name="username">
        <input type="password" name="password">
    </form>
    

    不要添加 thymeleaf springsecurity 依赖项。 我希望这可能会有所帮助

    【讨论】:

      【解决方案2】:

      原因是httpBasicformLogin默认开启CSRF防御。因为您的 POST 不包含 CSRF 令牌,所以 Spring Security 拒绝它。

      您可以通过更改配置以允许/error 端点来更好地了解这一点:

      http
          .authorizeRequests()
              .antMatchers("/", "/v1/occupancy/**", "/error").permitAll()
          // ...
      

      然后,当您提交 POST 时,您会看到与 CSRF 令牌拒绝相关的 403。

      如果您的 REST API 不是面向前端的,那么您可以关闭 CSRF。一种方法是禁用适当的端点:

      http
        .authorizeRequests()
          // ...
          .and()
        .csrf()
          .ignoringAntMatchers("/v1/admin/repository/establishment/options")
          // ...
      

      如果是正面的,那么合适的做法是prepare your front-end to hand the CSRF token back to the request

      【讨论】:

        猜你喜欢
        • 2021-11-15
        • 2020-04-30
        • 1970-01-01
        • 2018-10-15
        • 1970-01-01
        • 1970-01-01
        • 2014-12-25
        • 2018-04-19
        • 1970-01-01
        相关资源
        最近更新 更多