Saya mendapat solulion yang berfungsi menggunakan jawaban dari tautan @John dan @Arpad dan tautan @RobWinch
Saya menggunakan Spring Security 3.2.9 dan jQuery 1.10.2.
Perpanjang kelas Spring menyebabkan respons 4XX hanya dari permintaan AJAX:
public class CustomLoginUrlAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint {
public CustomLoginUrlAuthenticationEntryPoint(final String loginFormUrl) {
super(loginFormUrl);
}
// For AJAX requests for user that isn't logged in, need to return 403 status.
// For normal requests, Spring does a (302) redirect to login.jsp which the browser handles normally.
@Override
public void commence(final HttpServletRequest request,
final HttpServletResponse response,
final AuthenticationException authException)
throws IOException, ServletException {
if ("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) {
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access Denied");
} else {
super.commence(request, response, authException);
}
}
}
applicationContext-security.xml
<security:http auto-config="false" use-expressions="true" entry-point-ref="customAuthEntryPoint" >
<security:form-login login-page='/login.jsp' default-target-url='/index.jsp'
authentication-failure-url="/login.jsp?error=true"
/>
<security:access-denied-handler error-page="/errorPage.jsp"/>
<security:logout logout-success-url="/login.jsp?logout" />
...
<bean id="customAuthEntryPoint" class="com.myapp.utils.CustomLoginUrlAuthenticationEntryPoint" scope="singleton">
<constructor-arg value="/login.jsp" />
</bean>
...
<bean id="requestCache" class="org.springframework.security.web.savedrequest.HttpSessionRequestCache">
<property name="requestMatcher">
<bean class="org.springframework.security.web.util.matcher.NegatedRequestMatcher">
<constructor-arg>
<bean class="org.springframework.security.web.util.matcher.MediaTypeRequestMatcher">
<constructor-arg>
<bean class="org.springframework.web.accept.HeaderContentNegotiationStrategy"/>
</constructor-arg>
<constructor-arg value="#{T(org.springframework.http.MediaType).APPLICATION_JSON}"/>
<property name="useEquals" value="true"/>
</bean>
</constructor-arg>
</bean>
</property>
</bean>
Di JSP saya, tambahkan penangan kesalahan global AJAX seperti yang ditunjukkan di sini
$( document ).ajaxError(function( event, jqxhr, settings, thrownError ) {
if ( jqxhr.status === 403 ) {
window.location = "login.jsp";
} else {
if(thrownError != null) {
alert(thrownError);
} else {
alert("error");
}
}
});
Juga, hapus penangan kesalahan yang ada dari panggilan AJAX di halaman JSP:
var str = $("#viewForm").serialize();
$.ajax({
url: "get_mongoDB_doc_versions.do",
type: "post",
data: str,
cache: false,
async: false,
dataType: "json",
success: function(data) { ... },
// error: function (jqXHR, textStatus, errorStr) {
// if(textStatus != null)
// alert(textStatus);
// else if(errorStr != null)
// alert(errorStr);
// else
// alert("error");
// }
});
Saya harap ini membantu orang lain.
Update1
Saya menemukan bahwa saya perlu menambahkan opsi (selalu-gunakan-default-target = "true") ke konfigurasi form-login. Ini diperlukan karena setelah permintaan AJAX dialihkan ke halaman login (karena sesi kedaluwarsa), Spring mengingat permintaan AJAX sebelumnya dan auto redirect ke setelah login. Ini menyebabkan JSON yang dikembalikan ditampilkan pada halaman browser. Tentu saja, bukan yang saya inginkan.
Update2
Alih-alih menggunakan always-use-default-target="true"
, gunakan contoh @RobWinch untuk memblokir permintaan AJAX dari requstCache. Ini memungkinkan tautan normal untuk diarahkan ke target semula setelah login, tetapi AJAX pergi ke halaman utama setelah login.