问题
I'm struggling to return a json response when the user is nog logged in, instead of returning a html login form.
The application is only using @RestController's and I do not want any web support.
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.httpBasic().disable();
When I do a get request using the browser or postman, I receive back the default spring HTML login form.
security.basic.enabled=true
I'm using OATH2, and when I request a token it works great and I get a response like this:
{
"access_token": "227803d1-fe94-4e31-b496-3a03bafb9479",
"token_type": "bearer",
"refresh_token": "322f4ee9-4c48-4e06-a129-f4b6af93d664",
"expires_in": 43199,
"scope": "read write"
}
Somehow, it works correct in this example:
https://github.com/royclarkson/spring-rest-service-oauth
And when I'm not authorized, I want back something like this:
{
"error": "unauthorized",
"error_description": "An Authentication object was not found in the SecurityContext"
}
But I'm getting a login form, and I want the response above. What am I doing wrong? I litterally can't uderstand why it works in the GitHub example, and not in my case. Is there a way to completely disable the login form, and force the json response?
回答1:
AuthenticationEntryPoint is used for exception handling in spring security.
If you have added the oauth2 to your pom, you can use OAuth2AuthenticationEntryPoint for you entry point, the Entry point is for spring security exception handling, if you are using the basic for your authentication, you can config like this
http
.httpBasic().authenticationEntryPoint(getCustomerEntryPoint());
@Bean
protected AuthenticationEntryPoint getCustomerEntryPoint() {
return new OAuth2AuthenticationEntryPoint();
}
as you can see the exception handling in OAuth2AuthenticationEntryPoint
// Try to extract a SpringSecurityException from the stacktrace
Throwable[] causeChain = throwableAnalyzer.determineCauseChain(e);
Exception ase = (OAuth2Exception) throwableAnalyzer.getFirstThrowableOfType(
OAuth2Exception.class, causeChain);
if (ase != null) {
return handleOAuth2Exception((OAuth2Exception) ase);
}
ase = (AuthenticationException) throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class,
causeChain);
if (ase != null) {
return handleOAuth2Exception(new UnauthorizedException(e.getMessage(), e));
}
ase = (AccessDeniedException) throwableAnalyzer
.getFirstThrowableOfType(AccessDeniedException.class, causeChain);
if (ase instanceof AccessDeniedException) {
return handleOAuth2Exception(new ForbiddenException(ase.getMessage(), ase));
}
ase = (HttpRequestMethodNotSupportedException) throwableAnalyzer
.getFirstThrowableOfType(HttpRequestMethodNotSupportedException.class, causeChain);
if (ase instanceof HttpRequestMethodNotSupportedException) {
return handleOAuth2Exception(new MethodNotAllowed(ase.getMessage(), ase));
}
return handleOAuth2Exception(new ServerErrorException(e.getMessage(), e));
it will try to get OAuth2Exception, AuthenticationException, AccessDeniedException in order, I think you can use this.
And you can also config the ExceptionTranslationFilter, this filter is in the spring security chain, and it will catch and handler the exception after it, like AuthenticationException, AccessDeniedException, and it is main entry point and will be helpful for most authentication method, like FormLogin.
http
.exceptionHandling().authenticationEntryPoint(getCustomerEntryPoint());
If you are not use the spring oauth2, now you understand the AuthenticationEntryPoint, so you can also implement you own AuthenticationEntryPoint and custom your exception response, just overrider the commence method, like
BasicAuthenticationEntryPoint: it will return 'WWW-Authenticate' header
LoginUrlAuthenticationEntryPoint: it will redirect to target url when no authentcation
回答2:
Will need a custom AuthenticationEntryPoint and override the commence() method.
Indeed, the entry point has to be registered in the Spring Security config
http.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
Sample code:
public class UserAuthenticationEntryPoint implements
AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response, AuthenticationException ex)
throws IOException, ServletException {
response.setContentType("application/json");
response.getOutputStream().print("{\"error\":\"Unauthorized.. Please authenticate..\"}");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
}
}
来源:https://stackoverflow.com/questions/43088456/return-restful-json-response-instead-of-login-form-in-spring-boot-oauth2