簡體   English   中英

Spring 安全異常處理自定義響應

[英]Spring security exception handling custom response

怎么可能返回 json 而不是 html?

我有:

<!doctype html>
<html lang="en">

<head>
    <title>HTTP Status 401 – Unauthorized</title>
    <style type="text/css">
        body {
            font-family: Tahoma, Arial, sans-serif;
        }

        h1,
        h2,
        h3,
        b {
            color: white;
            background-color: #525D76;
        }

        h1 {
            font-size: 22px;
        }

        h2 {
            font-size: 16px;
        }

        h3 {
            font-size: 14px;
        }

        p {
            font-size: 12px;
        }

        a {
            color: black;
        }

        .line {
            height: 1px;
            background-color: #525D76;
            border: none;
        }
    </style>
</head>

<body>
    <h1>HTTP Status 401 – Unauthorized</h1>
</body>

</html>

我需要這樣的東西:

{
    "errors": [
        {
            "status": "401",
            "title": "UNAUTHORIZED",
            "detail": "xyz ..."
        }
    ]
}

我的適配器:

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
{
   @Override
   protected void configure(HttpSecurity httpSecurity) throws Exception
   {
      // @formatter:off
      httpSecurity
               .csrf()
               .disable()
               .authorizeRequests()
               .antMatchers(HttpMethod.GET).permitAll()
               .anyRequest()
               .authenticated()
               .and()
               .httpBasic()
               .and()
               .exceptionHandling()
               .authenticationEntryPoint(new CustomAuthenticationEntryPoint());
      // @formatter:on
   }
}

CustomAuthenticationEntryPoint

@Component
class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint
{
   @Override
   public void commence(HttpServletRequest request, HttpServletResponse response,
                        AuthenticationException authException) throws IOException
   {
      Collection<String> authorities = response.getHeaders("Authorization");
      response.addHeader("access_denied_reason", "authentication_required");
      response.sendError(HttpStatus.UNAUTHORIZED.value(), "Unauthorized");
   }
}

實際上,我們可以在入口點內打印/寫入response[.getWriter()] ,例如:

import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
//...
private static AuthenticationEntryPoint authenticationEntryPoint() {
  return (request, response, authException) -> {
    response.addHeader( // identic/similar to "basic" entry point
        "WWW-Authenticate", "Basic realm=\"Realm\""
    );
    // subtle difference to "basic" entry point :
    // better/looks like:
    response.setContentType(MediaType.APPLICATION_JSON_VALUE);
    // response.addHeader...
    response.setStatus(HttpStatus.UNAUTHORIZED.value() /*, no message!(?) */);
    // "print" custom to "response" (with String#format, jackson, gson... (templating fw...)):
    response.getWriter().format("""
      {
        "errors":[
          {
            "status": %d,
            "title": "%s",
            "detail": "%s"
          }
        ]
      }
      """,
      HttpStatus.UNAUTHORIZED.value(),
      HttpStatus.UNAUTHORIZED.name(),
      authException.getMessage() // or whatever message/params/format we see fit
    );
  };
}

BasicAuthenticationEntryPoint@github

然后我們可以通過這樣的測試:

package com.example.security.custom.entrypoint;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@WebMvcTest
class SecurityCustomEntrypointApplicationTests {

  @Autowired
  private MockMvc mvc;

  @Test
  void testUnauthorized() throws Exception {
    mvc
        .perform(post("/somewhere")) // no (basic) credentials(!), assuming no 404 :)
        .andDo(print())
        .andExpectAll(
            status().isUnauthorized(),
            header().exists("WWW-Authenticate"),
            jsonPath("$.errors[0].detail").exists(),
            jsonPath("$.errors[0].title").value("UNAUTHORIZED"),
            jsonPath("$.errors[0].status").value(401) // , ...
        );
  }
}

要使其適用於基本身份驗證“錯誤憑據”,另請參閱: https://stackoverflow.com/a/74547059/592355

重復/相關:

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM