java - 为什么 default-target-url 和 AJAX 调用总是得到 "GET: 403 Forbidden "?

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

我正在为我的 web 应用程序使用 Spring MVC 安全性。用户转到 localhost/CT/home,并在该页面中输入用户名和密码,然后转到/login。如果验证成功,则转到/loginCheck ,否则如果身份验证失败,则转到/checkVerification 。

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

spring-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是因为经过一番挖掘后我发现这个问题可能是由于跨域请求造成的。请帮我。过去三天我一直被这个问题困扰。

最佳答案

您的默认目标网址应该是 GET 请求而不是 post 请求,对于 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}"/>

关于java - 为什么 default-target-url 和 AJAX 调用总是得到 "GET: 403 Forbidden "?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35984001/

相关文章:

java - 是否可以从 MethodParameter 对象中获取参数的值?

java - 上一页 URL JSF

java - 按键中的属性分组时对值中的元素进行计数

java - 在 Camel 中使用聚合策略附加交换机构

java - 斯坦福 NLP 情感模糊结果

java - 将 A<X,Y> 类型转换为 A<Object,Object>

java - 持久性单元 : default Unable to build Hibernate SessionFactory - Hibernate

java - 获取 PathVariable 中的空值

java - @Profile 注释中的 AND 运算符

java - Spring Boot 中的嵌套映射不加载静态内容