【问题标题】:Does JSF support form based securityJSF 是否支持基于表单的安全性
【发布时间】:2012-05-21 13:50:08
【问题描述】:

我按照这个教程 security在本教程中提到为基于表单的安全性添加类似的内容

<form action="j_security_check" method=post>
    <p>username: <input type="text" name="j_username"></p>
    <p>password: <input type="password" name="j_password"></p>
    <p><input type="submit" value="submit"></p>
</form>

但在 JSF 表单中,我在 h:form 中没有操作属性,我将其设置为 j_security_check。在 JSF 中还需要使用 j_username 和 j_password 来提供基于表单的安全性?

谢谢

【问题讨论】:

    标签: jsf-2


    【解决方案1】:

    是的,此操作 URL 和字段名称对于 form based authentication 是必需的。这是在 servlet 规范中指定的。您可以在 JSF 页面中按原样使用它。唯一的区别是表单提交和身份验证完全由容器处理,而不是由 JSF。你不必担心这个。

    但是,如果您希望对表单提交过程进行更细粒度的控制,或者希望利用 JSF 内置验证和 ajax 功能等,那么您始终可以通过 JSF 托管 bean 中的programmatic authentication 来接管它。为此,您必须在操作方法中使用HttpServletRequest#login()。身份验证仍由容器处理。

    例如

    <h:form>
        <h:inputText value="#{login.username}" required="true" />
        <h:inputSecret value="#{login.password}" required="true" />
        <h:commandButton value="login" action="#{login.submit}">
            <f:ajax execute="@form" render="@form" />
        </h:commandButton>
        <h:messages />
    </h:form>
    

    public String submit() {
        FacesContext context = FacesContext.getCurrentInstance();
        HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
    
        try {
            request.login(username, password);
            return "home?faces-redirect-true";
        } catch (ServletException e) {
            context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Unknown login", null));
            return null;
        }
    }
    

    【讨论】:

    • HHm 谢谢,但是当我们使用request.login(username, password); 时,JSF 如何验证它。就像我输入 basit(用户)和 basit(密码)一样。我需要在 glassfish 服务器或数据库中的某处设置用户名密码吗?意味着 request.login() 如何工作?谢谢
    • 与基于表单的身份验证方式相同。唯一的区别是您以编程方式调用它,而不是使用j_usernamej_password 提交给j_security_check
    【解决方案2】:

    以下是我为在 Websphere 7 中运行的 JSF 应用程序实现 j_security_check(容器管理安全)的方法。不幸的是,我使用的 servlet api 版本没有

    request.login()
    

    创建了一个登录过滤器类来拦截 j_security_check 调用。 ResponseWrapper 记住登录后要重定向的 URL。

    public class LoginFilter implements Filter {
            private static String loginPage = "login.xhtml"; // read it from init config
        public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException {
            // TODO Auto-generated method stub
            // create wrapper
            HttpServletRequest req = (HttpServletRequest) request;
            MyWrapper myRes = new MyWrapper((HttpServletResponse) response);
            // call authentication
            chain.doFilter(request, myRes);
            // check for login error
                    String redirectURL = myRes.getOriginalRedirect();
              if (StringUtils.isBlank(redirectURL) || redirectURL.contains(loginPage)) {
                       myRes.setOriginalRedirect(homePage);
                  }
        myRes.sendMyRedirect();
    
    }
        class MyWrapper extends HttpServletResponseWrapper {
            String originalRedirect;
    
            public MyWrapper(HttpServletResponse response) {
                super(response);
            }
    
            @Override
            public void sendRedirect(String location) throws IOException {
                // just store location, don’t send redirect to avoid
                // committing response
                originalRedirect = location;
            }
    
            // use this method to send redirect after modifying response
            public void sendMyRedirect() throws IOException {
                super.sendRedirect(originalRedirect);
            }
    
            public String getOriginalRedirect() {
                return originalRedirect;
            }
    
            public void setOriginalRedirect(String originalRedirect) {
                this.originalRedirect = originalRedirect;
            }
    
    
        }
    

    web.xml 如下所示。

    <filter>
        <filter-name>LoginFilter</filter-name>
        <filter-class>com.servlet.filter.LoginFilter</filter-class>
    </filter>
    
    <filter-mapping>
        <filter-name>LoginFilter</filter-name>
        <url-pattern>/j_security_check</url-pattern>
    </filter-mapping>
    <filter>
        <filter-name>RequestJSFFilter</filter-name
            <filter-class>com.servlet.filter.RequestJSFFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>RequestJSFFilter</filter-name>
        <url-pattern>*.xhtml</url-pattern>
    </filter-mapping>
    

    另一个过滤器拦截所有 *.xhtml 并指向 login.xhtml。在 login.xhtml 中,表单可以如下所示

    <form action="j_security_check" method=post>
        <p>username: <input type="text" name="j_username"></p>
        <p>password: <input type="password" name="j_password"></p>
        <p><input type="submit" value="submit"></p>
    </form>
    

    希望这会有所帮助。

    【讨论】:

    • 这显然是特定于 Websphere 的。过滤器不能直接映射到/j_security_check,因为这将在进入特定于 webapp 的过滤器之前由容器处理。您的方法至少在 Tomcat、JBoss 和 Glassfish 中会失败。
    • 我同意这一点。我一直在寻找适用于 Websphere 的解决方案。不幸的是,我找不到一个。因此发布这个可以帮助某人。
    猜你喜欢
    • 2013-09-03
    • 2011-10-04
    • 2010-12-01
    • 1970-01-01
    • 2012-06-13
    • 1970-01-01
    • 1970-01-01
    • 2015-02-26
    • 1970-01-01
    相关资源
    最近更新 更多