gpt4 book ai didi

Spring 自定义 JSF 登录页面,总是 "Bad credentials"

转载 作者:行者123 更新时间:2023-12-01 12:51:58 28 4
gpt4 key购买 nike

我正在尝试让 JSF 登录页面与 Spring 安全性一起工作。我四处寻找了许多例子,但没有一个有效。每次我尝试使用 JSF 页面登录时,我都会在服务器日志中收到“错误凭据”警告。

Spring-Security.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">

<http auto-config="true">
<intercept-url pattern="/Login.xhtml*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/**/*.css*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/**/*.js*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/**" access="ROLE_USER,ROLE_ADMIN" />
<form-login login-page="/Login.xhtml" default-target-url="/Secure.xhtml"
authentication-failure-url="/Login.xhtml" />
</http>

<authentication-manager>
<authentication-provider>
<user-service>
<user name="admin" authorities="ROLE_ADMIN" password="admin"/>
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<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="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.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.xsd">

<context:component-scan base-package="com.example" />
<context:annotation-config />
<tx:annotation-driven />
<import resource="classpath:spring/security/Spring-Security.xml" />
</beans>

登录.xhtml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head></h:head>
<body>
<h:form>
<h:outputLabel value="username" for="j_username"
style="float:left" />
<h:inputText id="j_username" style="float:left" />

<h:outputLabel value="password" for="j_password"
style="float:left; clear:both" />
<h:inputSecret id="j_password" style="float:left" />

<h:commandButton value="login"
actionListener="#{loginBean.login}" style="float:left;clear:both" />
</h:form>
<h:messages style="float:left;clear:both" />
</body>
</html>

登录Bean

@Named
@Scope("request")
public class LoginBean
{
public void login() throws ServletException, IOException
{
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
externalContext.dispatch("/j_spring_security_check");
facesContext.responseComplete();
}
}

Web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<filter>
<filter-name>OpenEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
<init-param>
<param-name>singleSession</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>sessionFactoryBeanName</param-name>
<param-value>sessionFactory</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>OpenEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
</web-app>

当我将非 JSF 页面用作 Login.xhtml 时,它可以正常工作。

有效的页面:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head></h:head>
<body>
<form action="j_spring_security_check" method="post">
<table>
<tr>
<td>User:</td>
<td><input type="text" name="j_username" /></td>
</tr>
<tr>
<td>Password:</td>
<td><input type="password" name="j_password" /></td>
</tr>
<tr>
<td colspan='2'><input name="submit" type="submit"
value="submit" /></td>
</tr>
</table>
</form>
</body>
</html>

感谢任何帮助。

最佳答案

这是一个老问题。默认情况下,FilterSecurityInterceptor 只会对每个请求执行一次,并且不会进行安全性重新检查,除非 url 发生变化,但是对于 JSP/JSF 转发,页面将呈现为对当前请求的响应,并且 url 在浏览器包含上一页的地址。

在 Spring Security 3.0 之前,这被绕过做这样的 GET 请求:

String encodedURL = externalcontext.encodeResourceURL(externalcontext.getRequestContextPath() + "/j_spring_security_check?j_username=" + username + "&j_password=" + password);

externalcontext.redirect(encodedURL);

但是从Spring Security 3.0开始,默认只支持POST。

因此,最容易使用的一种方法可能是简单的 HTML 表单。否则,您需要通过获取 AuthenticationManager 手动验证请求。

我猜整个故事起源于这个post在 Spring 论坛上。

最好的工作示例可以在 ICEFaces wiki 上找到

这是 tutorial.zip 中的相关 LoginController 类

/**
* This class handles all login attempts except html forms that directly
* post to the /j_spring_security_check method.
*
* @author Ben Simpson
*/
@ManagedBean(name = "loginController")
@RequestScoped
public class LoginController implements Serializable {
private static final long serialVersionUID = 1L;


/**
* This action logs the user in and returns to the secure area.
*
* @return String path to secure area
*/
public String loginUsingSpringAuthenticationManager() {
//get backing bean for simple redirect form
LoginFormBackingBean loginFormBean =
(LoginFormBackingBean) FacesUtils.getBackingBean("loginFormBean");
//authentication manager located in Spring config: /WEB-INF/authenticationContext-security.xml
AuthenticationManager authenticationManager =
(AuthenticationManager) getSpringBean("authenticationManager");
//simple token holder
Authentication authenticationRequestToken = createAuthenticationToken(loginFormBean);
//authentication action
try {
Authentication authenticationResponseToken =
authenticationManager.authenticate(authenticationRequestToken);
SecurityContextHolder.getContext().setAuthentication(authenticationResponseToken);
//ok, test if authenticated, if yes reroute
if (authenticationResponseToken.isAuthenticated()) {
//lookup authentication success url, or find redirect parameter from login bean
return "/secure/examples";
}
} catch (BadCredentialsException badCredentialsException) {
FacesMessage facesMessage =
new FacesMessage("Login Failed: please check your username/password and try again.");
FacesContext.getCurrentInstance().addMessage(null,facesMessage);
} catch (LockedException lockedException) {
FacesMessage facesMessage =
new FacesMessage("Account Locked: please contact your administrator.");
FacesContext.getCurrentInstance().addMessage(null,facesMessage);
} catch (DisabledException disabledException) {
FacesMessage facesMessage =
new FacesMessage("Account Disabled: please contact your administrator.");
FacesContext.getCurrentInstance().addMessage(null,facesMessage);
}

return null;
}

private Authentication createAuthenticationToken(LoginFormBackingBean loginFormBean) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
new UsernamePasswordAuthenticationToken(
loginFormBean.getUserName(),
loginFormBean.getPassword()
);
return usernamePasswordAuthenticationToken;
}


private Object getSpringBean(String name){
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(
(ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext());
return ctx.getBean(name);
}
}

选项 3:我还没有亲自尝试过,但即使这样也应该可行:

通过在 applicationContext 的 http 元素中将 once-per-request 属性设置为 false,从而强制进行安全性重新检查。但我不推荐它。

<http auto-config="true" use-expressions="true" once-per-request="false">

关于Spring 自定义 JSF 登录页面,总是 "Bad credentials",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11742283/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com