How to return JSON response for unauthorized AJAX

2019-08-08 17:29发布

问题:

I have implemented Spring Security in my application. Whenever someone tries to access any url if authentication is required for these urls user will be redirected to login page. Now, if AJAX call is made for any such url I would like to return JSON response instead of login page's HTML as AJAX response. How can I do that ?

回答1:

You have to create json for this i am doing here with .net
var url="url";
$.ajax({
    type: "get",
    dataType: "json",
    data:url,
    async: true,
    url: "testCall",//this can be your api or any server side call
    success: function (data) {      
    },
    failure: function () {
        alert(textStatus);
}
});

//here is server side code for creating json

[WebMethod(EnableSession = true)]
[ScriptMethod(UseHttpGet = true)]
public void testCall(string url)
{
 Context.Response.Write()//here your will just hard code the json data
//it will receive by ajax success method.
}


回答2:

Faced the same thing not long ago, came out with this solution.

You'll have to redefine the authentication entry point to handle the exception and returning a proper JSON response.

First create a class for your response. Needs to be a POJO.

public class MyErrorResponse {
    // your stuff here, and getters / setters
}

Then go define the authentication entry point

public class MyBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {

    private List<HttpMessageConverter<Object>> messageConverters = new ArrayList<>();

    private MediaType retrieveRequestMediaType(HttpServletRequest request) {
        String accept = request.getHeader("accept");

        if(Strings.isNullOrEmpty(accept))
            accept = MediaType.APPLICATION_JSON_VALUE;

        MediaType requestMediaType = MediaType.valueOf(accept);

        return requestMediaType;
    }

    private HttpMessageConverter<Object> retrieveMessageConverter(List<HttpMessageConverter<Object>> messageConverters, Class<?> clazz, MediaType mediaType) {
        for (HttpMessageConverter<Object> httpMessageConverter : messageConverters) {
            if(httpMessageConverter.canWrite(clazz, mediaType)) {
                return httpMessageConverter;
            }
        }
    }

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        log.warn(String.format("Unauthorized access with session id '%s'", request.getSession().getId()));

        MyErrorResponse esponse = new MyErrorResponse();
        // populate your response object with all the info you need

        MediaType mediaType = MediaType.APPLICATION_JSON;
        try{
            mediaType = retrieveRequestMediaType(request);
        } catch(InvalidMediaTypeException imte) {
            // log, do nothing
        }

        // getting the best fitting message converter, according to the "accept" header of the request
        HttpMessageConverter<Object> httpMessageConverter = retrieveMessageConverter(messageConverters, MyErrorResponse.class, mediaType);

        if(httpMessageConverter == null) {
            log.info("Could not find specific handler. Using JSON.");
            httpMessageConverter = retrieveMessageConverter(messageConverters, MyErrorResponse.class, MediaType.APPLICATION_JSON);
        }

        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        ServletServerHttpResponse serverHttpResponse = new ServletServerHttpResponse(errorResponse);
        httpMessageConverter.write(response, mediaType, serverHttpResponse);
    }

}

Once you got your bean set up, time to wire it up in the security context:

<beans:bean class="[fully qualified name of the entry point class]" id="myBasicAuthenticationEntryPoint">
    <beans:property name="messageConverters">
        <beans:list>
            <!-- add message converters here -->
            <!-- Spring provide lots of them, google it -->
        </beans:list>
    </beans:property>
</beans:bean>
<http use-expressions="true">
    <http-basic entry-point-ref="myBasicAuthenticationEntryPoint" />
    <!-- add other stuff here, if needed -->
</http>

Hope it helps