为什么我总是为default-target-url和AJAX调用获得“GET:403 Forbidden”?

时间:2016-03-14 09:40:20

标签: java spring spring-mvc spring-security spring-boot

我正在为我的webapp使用Spring MVC安全性。用户进入localhost / CT / home,在该页面输入用户名和密码进入/ login。如果成功验证将转至/ loginCheck,否则如果验证失败,则转至/ checkVerification。

调试并尝试BasicAuthenticationFilter后,我仍然得到403 Forbidden。

弹簧security.xml文件

<?xml version="1.0" encoding="UTF-8"?>

<b:beans xmlns="http://www.springframework.org/schema/mvc"
    xmlns:b="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:security="http://www.springframework.org/schema/security"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">

    <tx:annotation-driven transaction-manager="transactionManager"/> 
    <b:bean class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler"/>

        <security:http auto-config='true' use-expressions='true'>
         <security:form-login login-page="/login" default-target-url="/loginCheck" 
            authentication-failure-url="/checkVerification" 
            username-parameter="mobile_Number"
            password-parameter="password"
            always-use-default-target="true"/> 
          <security:intercept-url pattern="/loginCheck" access="hasRole('VERIFIED_USER')"/>
          <security:intercept-url pattern="/loginSuccess" />
          <security:intercept-url pattern="/home" access="permitAll" />
          <security:intercept-url pattern="/RankOption/**" access="hasRole('VERIFIED_USER')"/>
          <security:logout logout-url="/logout"/>
           <security:custom-filter ref="basicAuthenticationFilter"
            after="BASIC_AUTH_FILTER" />
    </security:http>


       <security:authentication-manager erase-credentials="false" alias="authenticationManager">
            <security:authentication-provider ref="myAuthenticationProvider">
            </security:authentication-provider> 
       </security:authentication-manager> 

    <b:bean id="bcryptEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />

    <b:bean id="myAuthenticationProvider" class="com.CT.www.provider.CustomAuthenticationProvider">

    </b:bean>   

    <security:global-method-security secured-annotations="enabled"/>



    <b:bean id="personService" class="com.CT.www.service.PersonServiceImpl">
        <b:property name="personDAO" ref="personDAO"></b:property>
    </b:bean>

    <b:bean id="personDAO" class="com.CT.www.dao.PersonDAOImpl">
        <b:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory" />
    </b:bean> 
<!-- For hashing and salting user passwords -->
    <b:bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>   





    <b:bean id="basicAuthenticationFilter" class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
        <b:constructor-arg ref="authenticationManager" />
         <b:constructor-arg ref="authenticationEntryPoint" />

    </b:bean>

     <b:bean id="authenticationEntryPoint" 
        class="com.CT.www.provider.PlainTextBasicAuthenticationEntryPoint">
        <b:property name="realmName" value="http://localhost:8080" />
    </b:bean> 

    <b:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <b:property name="driverClassName" value="com.mysql.jdbc.Driver" /> 
        <b:property name="url"
            value="jdbc:mysql:<ipAddress>/testDB" />
        <b:property name="username" value="root" />
        <b:property name="password" value="<password>" />
    </b:bean>

    <!--  Form Validator -->

    <b:bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <b:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory" />
    </b:bean> 


    <!-- Hibernate 4 SessionFactory Bean definition -->
    <b:bean id="hibernate4AnnotatedSessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <b:property name="dataSource" ref="dataSource" />
        <b:property name="packagesToScan">
            <b:list>
                <b:value>com.CT.www.model</b:value>

            </b:list>
        </b:property>
        <b:property name="hibernateProperties">
            <b:props>
                <b:prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect
                </b:prop>
                <b:prop key="hibernate.show_sql">true</b:prop>
            </b:props>
        </b:property>
    </b:bean>

    <context:component-scan base-package="com.CT.www" /> 


    <annotation-driven />

<!--    Handles HTTP GET requests for /resources/** by efficiently serving 
        up static resources in the ${webappRoot}/resources directory -->
    <resources mapping="/resources/**" location="/resources/" />

    <!-- Resolves views selected for rendering by @Controllers to .jsp resources 
        in the /WEB-INF/views directory -->
    <b:bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <b:property name="prefix" value="/WEB-INF/views/" />
        <b:property name="suffix" value=".jsp" />
    </b:bean>


</b:beans>

homePage.jsp

<c:url var="login_Var" value="/loginSuccess" ></c:url>
<form:form action="${login_Var}" name="loginForm" id="loginForm" method="POST">     
                            <table> 
                                <tr>                                    
                                    <td style="padding-right:10px;">
                                        <input type="text" name="mobile_Number" id="mobile_Number_SignIn" placeholder="Mobile number" disabled="disabled"
                                        class="login" 
                                        style="font-size:15px;border:4px;border: 2px solid #c3c5da;height: 35px; border-radius: 4px;font-size: 15px;" >
                                    </td>
                                    <td style="padding-right:10px;">
                                        <input type="password" name="password" id="password_Id" placeholder="Password" disabled="disabled" class="login" 
                                        style="font-size:15px;border:4px;border: 2px solid #c3c5da;height: 35px; border-radius: 4px;font-size: 15px;">      
                                    </td>
                                    <td>
                                    <!--     <input type="submit" name="loginS" value="Log In" id="loginSuccess" style="display:none;" >  -->
                                        <input type="button" id="login" value="Log In" onclick="login_fntn(mobile_Number_SignIn, password_Id, cCode)" 
                                        disabled="disabled" style="padding:3px;font-weight:bold;background-color:white;"/> 

                                    </td>
                                </tr>
                                <tr>
                                    <td style="padding-right:145px;" >
                                    </td>
                                    <td style="padding-top:5px;">

                                        <a href="#" id="forgotPassword" style="font-weight:normal;font-size:13px;">Forgot your password?</a>
                                    </td>

                                </tr>
                            </table>
                                <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
                        </form:form>                        

.
.
.
.

function login_fntn(mobile_Number_SignIn, password, cCode){
                var token = $("meta[name='_csrf']").attr("content");
                var header = $("meta[name='_csrf_header']").attr("content");


                var mobi_Number = document.getElementById("mobile_Number_SignIn").value;
                var password = document.getElementById("password_Id").value;
                var cCode = document.getElementById("cCode").value;
                mobi_Number = cCode + mobi_Number;
                /* var json_LogIn = JSON.stringify({"mobile_Number" : mobi_Number , "password" : password });
                 */

                var datum = [];
                 datum.push({
                    name: "mobile_Number",
                    value: mobi_Number
                }); 
                 datum.push({name:"password",value:password});
                   alert(datum.length + "after " + datum[0].value + datum[1].value);
                 jQuery.support.cors = true;
                 $.ajax({

                    url : "/CT/login",
                    type: "POST",
                    /* contentType: "application/json; charset=utf-8", 
                    dataType: "json",   */
                    cache: true,
                   /*  data: json_LogIn, */
                    data: datum,
                    beforeSend: function(xhr) {
                        xhr.setRequestHeader(header, token);                        
                    }, 
                    success : function(response){
                        /* alert(response); Mar22016 */
                        //if response = true , make a request to a method that returns home //this alone will make another db call from UI.
                        //else if response = false, show the dialog box of submit verification
                        //else if response = signup, open up the sign up dialog box.

                            if(response=="true"){
                            /*  $.ajax({

                                    url : "/CT/loginSuccess",
                                    type: "POST",
                                    contentType: "application/json; charset=utf-8",
                                    dataType: "json",   
                                    data: json_LogIn,
                                    beforeSend: function(xhr) {
                                        xhr.setRequestHeader(header, token);                        
                                    }
                                });          */             
                                /* alert("here"); Mar22016 */

                                document.getElementById("mobile_Number_SignIn").value = mobi_Number;
                                document.getElementById("loginForm").submit();


                            }else if(response == 1){

                            //user not registered yet. show dialog boxes. // the main reason why I resend the form in above if condition and do verification stuff again is because if successful it returns logical view. if not it will show dialog boxes(using ajax) to sign up users.
                        }

PlainTextBasicAuthenticationEntryPoint.java

public class PlainTextBasicAuthenticationEntryPoint extends 
BasicAuthenticationEntryPoint{

     @Override
     public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
         response.addHeader("Access-Control-Allow-Origin", "null");
         response.addHeader("WWW-Authenticate", "Basic realm=\"" + getRealmName() + "\"");
         response.setStatus(HttpServletResponse.SC_ACCEPTED);
     }
}

SomeController.java 如果我将以下方法loginCheck方法更改为GET,仍然无法正常工作

 @RequestMapping(value="/loginCheck", method = RequestMethod.POST)
    @ResponseBody
    public String loginCheck(){

        System.out.println("Inside login check");
        return "true";
    }   

    @RequestMapping(value="/loginSuccess", method = RequestMethod.POST)
    public ModelAndView loginSuccess(){


        System.out.println("Login 2");

    }

我介绍了BasicAuthenticationFilter,因为经过一些挖掘后我发现这个问题可能是因为跨域请求。请帮我。过去3天我对此问题感到震惊。

1 个答案:

答案 0 :(得分:1)

您的默认目标网址应该是GET请求而不是发布请求,对于ajax,您不应该加载csrf参数两次,最好只有两个在元标记中使用它。

@RequestMapping(value = {"/welcome" }, method = RequestMethod.GET)
    public ModelAndView defaultPage(Principal pricipal,HttpServletRequest request) {
        ModelAndView model = new ModelAndView();
        model.setViewName("index");
        return model;
    }
 $( document ).ajaxStart(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);
  });
});

<meta name="_csrf" content="${_csrf.token}"/>
<!-- default header name is X-CSRF-TOKEN -->
<meta name="_csrf_header" content="${_csrf.headerName}"/>