403 Forbidden Error with ajax GET request Spring

27,687

Solution 1

It is usually caused by Spring default CSRF protection.

If you use for example DELETE HTTP request from your JS code, it is required to send also CSRF protection headers.

It is not necessary to disable CSRF protection! Please, do not do that if not necessary.

You can easily add CSRF AJAX/REST protection by:

1.Adding meta headers to every page (use @layout.html or something):

<head>
  <meta name="_csrf" th:content="${_csrf.token}"/>
  <meta name="_csrf_header" th:content="${_csrf.headerName}"/>
</head>

2.Customizing your ajax requests to sent these headers for every request:

$(function () {
  var token = $("meta[name='_csrf']").attr("content");
  var header = $("meta[name='_csrf_header']").attr("content");
  $(document).ajaxSend(function(e, xhr, options) {
    xhr.setRequestHeader(header, token);
  });
});

Notice that i use thymeleaf, so i use th:content instead of content attribute.

Solution 2

If you are using Spring Security 3.2R1 and above try using this solution http://spring.io/blog/2013/08/21/spring-security-3-2-0-rc1-highlights-csrf-protection

Solution 3

As of Spring Security 4.0, CSRF protection is enabled by default with XML configuration. If you would like to disable CSRF protection, the corresponding XML configuration can be seen below.

<security:http use-expressions="true">
           ...
   <security:csrf disabled="true" />
</security:http>

Solution 4

Check files permissions. 403 is server error, not Ajax. Try to check requested file (by file i mean url) directly.

Share:
27,687
Maff
Author by

Maff

Updated on July 24, 2022

Comments

  • Maff
    Maff almost 2 years

    I am getting a 403 forbidden-error every time I try GET a user's information from the database. Relating to my code below, every time I try request by pressing the Ajax Test button, It fails to run and gives me an alert, but also in the console gives me a 403 Forbidden-error. I am not sure whether it has something to do with Spring security?

    Users JSP page:

    <table>
        <tr>
            <td>User Id</td>
            <td>Full Name</td>
            <td>Username</td>
            <td>Email</td>
            <td>Date of Birth</td>
            <td>User Authority</td>
            <td>Update </td>
            <td>Delete</td>
        </tr>
        <c:forEach var="user" items="${users}">
            <tr>
                <td><c:out value="${user.id}" /></td>
                <td><c:out value="${user.name}"/></td>
                <td><c:out value="${user.username}"/></td>
                <td><c:out value="${user.email}"/></td>
                <td><c:out value="${user.dob}"/></td>
                <td><c:out value="${user.authority}"/></td>
                <td>
                    <a id="update" href="<c:url value="/viewUser"><c:param name="id" value="${user.id}"/></c:url>"><button>Update</button></a>
                </td>
                <td>
                    <a id="delete" href="<c:url value="/deleteUser"><c:param name="id" value="${user.id}"/></c:url>"><button>Delete</button></a>
                </td>
                <td>
                    <button class="loadUser" name="id" value="${user.id}">Ajax test</button>
                </td>
            </tr>
        </c:forEach>
    </table>
     <div id="personIdResponse"> </div>
    <script type="text/javascript">
        $(document).ready(function(){
            $(".loadUser").click(function(e) {
                e.preventDefault();
                var personId = +$(this).val();
                $.get('${pageContext.request.contextPath}/SDP/ajaxTest/' + personId, function(user) {
                      $('#personIdResponse').text(user.name + ', = username ' + user.username);
                    })
                .fail(function(user){
                    alert('Could not load user');
                });
            });
        });
    </script>
    

    User Controller class:

        @RequestMapping("/viewUser")
    public String updateUser(Model model, @RequestParam(value = "id", required = false) Integer id) {
    
        User user = usersService.getUser(id);
    
        model.addAttribute("user", user);
    
        return "settings";
    }
    
    @RequestMapping("/ajaxTest")
    @ResponseBody
    public User ajaxTest(@RequestParam(value = "id", required = false) Integer id) {
    
        User user = usersService.getUser(id); 
        return user;
    }
    
  • Maff
    Maff over 10 years
    I just tried implementing this, but I got the exact same problem.
  • Maff
    Maff over 10 years
    @RequestMapping(value="/ajaxTest/{personId}", method=RequestMethod.GET) @ResponseBody public User ajaxTest(@PathVariable Integer personId) { User user = usersService.getUser(personId); return user; } That is my update code in the controller.
  • harsh
    harsh over 10 years
    Can you post your rest-servlet.xml as well? looks like by @ResponseBody you are expecting json conversion, do you have have jackson jar in classpath? not sure if this might be the case for 403 for Spring REST, but better to check..
  • harsh
    harsh over 10 years
    Also, what's your controller's RequestMapping url?
  • Maff
    Maff over 10 years
    I havn't got a rest-servlet.xml config file. I do have the jackson jar in the class path though.
  • harsh
    harsh over 10 years
    Without proper json conversion your req wouldn't succeed. Check json mapping configuration ibm.com/developerworks/library/wa-restful (listing-1), this should help.
  • Vineet Kasat
    Vineet Kasat over 10 years
    @Harsh If there is no matching resource at server side in Spring then 404 error is thrown, not 403. Also error codes have nothing to do with framework, it is tomcat dependent.
  • harsh
    harsh over 10 years
    It is not tomcat dependent at least in this case, 404 is a sure case of not having matching resource (based on url) but 403 can come if operation is not allowed (e.g. accept-type in request is txt but at resource it is configured as json, this is one of a 403 case and surely not 404)
  • harsh
    harsh over 10 years
    @VineetKasat My above comment is purely based on REST spec (jsr-311) and implementation (in this case Spring REST) which has nothing to do with tomcat or any other web-server.
  • Vineet Kasat
    Vineet Kasat over 10 years
    @Harsh 403 can come if request is broken. 403 means request has not reached server.
  • harsh
    harsh over 10 years
    Not true (in some cases it may be), 403 in case is always sent either by REST container (i.e. Jersey, Spring REST) or by application code (i.e. apps authentication filter where on auth failure Response.FORBIDDEN is thrown, stackoverflow.com/a/6527453/878732). ResponseCode javadoc jersey.java.net/nonav/apidocs/1.5/jersey/javax/ws/rs/core/… which is heavily used by application code to return specific status.
  • zeleven
    zeleven over 6 years
    What is the _csrf.headerName?
  • tomasz_kusmierczyk
    tomasz_kusmierczyk over 6 years
    @H.鄭 start trying with X-CSRF-TOKEN