次の認証エラーをカスタマイズできるかどうか疑問に思いました。
{
"error": "unauthorized",
"error_description": "Full authentication is required to access this resource"
}
ユーザーリクエストに権限がない場合に取得します。そして、SpringBootエラーと非常によく似たものになるようにカスタマイズしたいと思います。
{
"timestamp":1445441285803,
"status":401,
"error":"Unauthorized",
"message":"Bad credentials",
"path":"/oauth/token"
}
それは可能でしょうか?
どうもありがとう。
わかった :)
https://stackoverflow.com/a/37132751/2520689
次のように「AuthenticationEntryPoint」を実装する新しいクラスを作成する必要があります。
public class AuthExceptionEntryPoint implements AuthenticationEntryPoint
{
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException arg2) throws IOException, ServletException
{
final Map<String, Object> mapBodyException = new HashMap<>() ;
mapBodyException.put("error" , "Error from AuthenticationEntryPoint") ;
mapBodyException.put("message" , "Message from AuthenticationEntryPoint") ;
mapBodyException.put("exception", "My stack trace exception") ;
mapBodyException.put("path" , request.getServletPath()) ;
mapBodyException.put("timestamp", (new Date()).getTime()) ;
response.setContentType("application/json") ;
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED) ;
final ObjectMapper mapper = new ObjectMapper() ;
mapper.writeValue(response.getOutputStream(), mapBodyException) ;
}
}
そしてそれを私のResourceServerConfigurerAdapter実装に追加します:
@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter
{
@Override
public void configure(HttpSecurity http) throws Exception
{
http.exceptionHandling().authenticationEntryPoint(new AuthExceptionEntryPoint()) ;
}
}
必要なものすべてを実装する私のGitHubプロジェクトを見つけることができます。
受け入れられた回答は、Oauth2を使用している私には機能しません。いくつかの調査の後、 例外トランスレータソリューション が機能します。
基本的に、WebResponseExceptionTranslator
を作成し、それを例外トランスレータとして登録する必要があります。
まず、WebResponseExceptionTranslator
Beanを作成します。
@Slf4j
@Configuration
public class Oauth2ExceptionTranslatorConfiguration {
@Bean
public WebResponseExceptionTranslator oauth2ResponseExceptionTranslator() {
return new DefaultWebResponseExceptionTranslator() {
@Override
public ResponseEntity<OAuth2Exception> translate(Exception e) throws Exception {
ResponseEntity<OAuth2Exception> responseEntity = super.translate(e);
OAuth2Exception body = responseEntity.getBody();
HttpStatus statusCode = responseEntity.getStatusCode();
body.addAdditionalInformation("timestamp", dateTimeFormat.format(clock.instant()))
body.addAdditionalInformation("status", body.getHttpErrorCode().toString())
body.addAdditionalInformation("message", body.getMessage())
body.addAdditionalInformation("code", body.getOAuth2ErrorCode().toUpperCase())
HttpHeaders headers = new HttpHeaders();
headers.setAll(responseEntity.getHeaders().toSingleValueMap());
// do something with header or response
return new ResponseEntity<>(body, headers, statusCode);
}
};
}
}
次に、Oauth2構成を変更してBean WebResponseExceptionTranslator
を登録する必要があります。
@Slf4j
@Configuration
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private ClientDetailsServiceBuilder builder;
@Autowired
private WebResponseExceptionTranslator oauth2ResponseExceptionTranslator;
@Autowired
private UserDetailsService userDetailsService;
@Override
public void configure(ClientDetailsServiceConfigurer clients) {
clients.setBuilder(builder);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(
Arrays.asList(tokenEnhancer(), accessTokenConverter()));
endpoints.tokenStore(tokenStore())
.tokenEnhancer(tokenEnhancerChain)
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService)
.exceptionTranslator(oauth2ResponseExceptionTranslator);
}
}
最終結果は次のようになります。
{
"error": "unauthorized",
"error_description": "Full authentication is required to access this resource",
"code": "UNAUTHORIZED",
"message": "Full authentication is required to access this resource",
"status": "401",
"timestamp": "2018-06-28T23:55:28.86Z"
}
OAuth2Exceptionの元の本体からerror
とerror_description
を削除していないことがわかります。これらの2つのフィールドはOAuth2仕様に従っているため、これらを維持することをお勧めします。詳細については、 RFC および OAuth2 API定義 を参照してください。
結果をカスタマイズすることもできます。error
またはerror_description
をオーバーライドし(addAdditionalInformation
を呼び出すだけ)、instance of
で特定の例外を識別して、別のjson結果を返すなど。 。しかし、制限もあります。あるフィールドをinteger
として定義したい場合、addAdditionalInformation
メソッドはString
のみを型として受け入れるため、それは不可能だと思います。
ストーリーショート:https://github.com/melardev/JavaSpringBootOAuth2JwtCrudPagination.git
@ pakkkの応答を読んだ後、同意しなかったので、自分で考えてみることにしましたが、これも失敗しました。そこで、Spring Securityのソースコード自体を確認することにしました。非常に早い段階で呼び出されるフィルター、OAuth2AuthenticationProcessingFilter。このフィルターはヘッダーからJWTを抽出しようとします。例外がスローされると、そのauthenticationEntryPoint.commence()が呼び出されます(@pakkはここにあります)フィルターを追加して、JWTが無効なときに呼び出されるかどうかを確認しようとしました存在し、そうではなかったため、応答を変更するためのカスタムフィルターを追加しても機能しません。次に、OAuth2AuthenticationProcessingFilterが構成されている場所を調べたところ、ResourceServerSecurityConfigurer :: configure(HttpSecurity http)で構成されていることがわかりました。そうは言っても、プロセスにフックする方法を見てみましょう。 Resource ServerアプリケーションでResourceServerConfigurerAdapterクラスを拡張するので、非常に簡単であることがわかります。
@Configuration
@EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
// ....
}
先に進み、オーバーライドします。
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
super.configure(resources);
}
ご覧のとおり、そうです! ResourceServerSecurityConfigurerにアクセスできるので、今は何ですか?さて、デフォルトのエントリポイントを私たちのものに置き換えましょう:
@Autowired
private AuthenticationEntryPoint oauthEntryPoint;
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
super.configure(resources);
resources.authenticationEntryPoint(oauthEntryPoint);
}
例を含む完全なソースコードについては、次を参照してください。 https://github.com/melardev/JavaSpringBootOAuth2JwtCrudPagination.git
この手順がないと、少なくとも私にとっては機能せず、@ pakkkによって提供される応答は機能しません。デバッガーをチェックしました。デフォルトでは、使用されるエントリポイントは、次を使用しても私たちのものではありません。
http.and().exceptionHandling().authenticationEntryPoint(oauthEntryPoint)
これは私が最初にテストしたことでした。それを機能させるには、ResourceServerSecurityConfigurerクラスから直接エントリポイントを変更する必要があります。
これが私のエントリポイントです。自分のクラスであるErrorResponseオブジェクトを送信しているので、応答を完全に制御できます。
@Component
public class OAuthEntryPoint implements AuthenticationEntryPoint {
@Autowired
ObjectMapper mapper;
@Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
ServletServerHttpResponse res = new ServletServerHttpResponse(httpServletResponse);
res.setStatusCode(HttpStatus.FORBIDDEN);
res.getServletResponse().setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
res.getBody().write(mapper.writeValueAsString(new ErrorResponse("You must authenticated")).getBytes());
}
}