我正在为我的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天我对此问题感到震惊。
答案 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}"/>