Spring Security无法在身份验证后重定向页面

时间:2012-08-16 05:22:53

标签: jsf-2 spring-security

我有一个安装了spring security的JSF项目,我使用forward方法进行登录。但我无法将页面重定向到AuthenticationBean.java中的secured.xhtml。似乎“forward()”方法导致了这一点。但是身份验证成功完成,我无法重定向页面。 如果没有forward方法,我可以成功重定向页面。那么,帮忙吗?

的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>

    <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>

    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>

    <welcome-file-list>
        <welcome-file>index.xhtml</welcome-file>
    </welcome-file-list>

    <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>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/spring-security.xml
        </param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>

弹簧security.xml文件

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

<security:http auto-config="true" use-expressions="true" access-denied-page="/denied.xhtml">

    <security:intercept-url pattern="/login.xhtml" access="permitAll"/>
    <security:intercept-url pattern="/secured.xhtml" access="hasRole('ROLE_ADMIN')"/>

    <security:form-login
    login-page="/login.xhtml"
    authentication-failure-url="/login.xhtml?error=true"
    default-target-url="/"/>

    <security:logout
    invalidate-session="true"
    logout-success-url="/index.xhtml"
    logout-url="/logout.xhtml"/>

</security:http>

<security:authentication-manager>
    <security:authentication-provider user-service-ref="customUserDetailsService">
    <security:password-encoder ref="passwordEncoder"/>
    </security:authentication-provider>
</security:authentication-manager>

<bean class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" id="passwordEncoder"/>

   <bean id="customUserDetailsService" class="com.triune.services.CustomUserDetailsService"/>

</beans>

CustomUserDetailService.java(永远不会调用它)

package com.triune.services;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import com.triune.dao.UserDAO;
import com.triune.entities.LoginCredential;
import org.springframework.dao.DataAccessException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.transaction.annotation.Transactional;

@Transactional(readOnly = true)
public class CustomUserDetailsService implements UserDetailsService {

    private UserDAO userDAO = new UserDAO();
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException 
    {
        UserDetails user = null;

        try
        {
            LoginCredential dbUser = userDAO.searchDatabase(username);

            user =  new User(
                dbUser.getUsername(),
                dbUser.getPassword().toLowerCase(),
                true,
                true,
                true,
                true,
                getAuthorities(dbUser.getAccess()) 
            );
        }
        catch (Exception e) 
        {
            throw new UsernameNotFoundException("Error in retrieving user");
        }       
        return user;
    }

    public Collection<GrantedAuthority> getAuthorities(Integer access) 
    {
        List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>(2);

        authList.add(new SimpleGrantedAuthority("ROLE_USER"));

        if ( access.compareTo(1) == 0) 
        {
            authList.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
        }

        return authList;
    }
}

AuthenticationBean.java(由登录页面调用)

package com.triune.beans;

import java.io.IOException;
import java.io.Serializable;
import javax.enterprise.context.SessionScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.inject.Named;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

@Named("authenticationBean")
@SessionScoped
public class AuthenticationBean implements Serializable
{
    public String doLogin() throws IOException, ServletException
    {
        ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
        RequestDispatcher dispatcher = ((ServletRequest)context.getRequest()).getRequestDispatcher("j_spring_security_check");
        dispatcher.forward((ServletRequest)context.getRequest(), (ServletResponse)context.getResponse());
        FacesContext.getCurrentInstance().responseComplete();
        return "secured.xhtml";
    }

    public String doLogout()
    {
        FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
        return "index.xhtml";
    }
}

login.xhtml(简单登录页面)

<?xml version='1.0' encoding='UTF-8' ?>
<!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:p="http://primefaces.org/ui">
    <h:head>
        <title>Login Page</title>
    </h:head>
    <h:body>
        <h1>Login Please</h1>
        <p>This is a really simple login page.</p>
        <h:form id="loginForm" prependId="false">
            <h:panelGroup>
                Username : <p:inputText id="j_username" required="true"/>
            </h:panelGroup>
            <br/>
            <h:panelGroup>
                Password : <p:inputText id="j_password" required="true"/>
            </h:panelGroup>
            <br/><br/>
            <h:panelGroup>
                <p:commandButton type="submit" id="login" action="#{authenticationBean.doLogin()}" value="login"/>
            </h:panelGroup>
        </h:form>
    </h:body>
</html>

1 个答案:

答案 0 :(得分:0)

在JSF中,当您在操作方法上返回String时,它默认触发转发而不是重定向(除非您在faces-config.xml上配置了导航规则并在其上放置了<redirect />)。

在你的情况下,你可以从ExternalContext中调用redirect()而不是返回一个String:

在你的utils类中添加一个这样的方法(或者自己OmniFaces):

public static void redirect(String url) throws IOException {
    ExternalContext ctx = FacesContext.getCurrentInstance()
        .getExternalContext();
    if (url.startsWith("http://") || url.startsWith("https://")
            || url.startsWith("/")) {
        ctx.redirect(url);
    } else {
        ctx.redirect(ctx.getRequestContextPath() + "/" + url);
    }
}

并更改您的方法doLogin()

public void doLogin() throws IOException, ServletException
{
    ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
    RequestDispatcher dispatcher = ((ServletRequest)context.getRequest()).getRequestDispatcher("j_spring_security_check");
    dispatcher.forward((ServletRequest)context.getRequest(), (ServletResponse)context.getResponse());
    FacesContext.getCurrentInstance().responseComplete();
    redirect("secured.xhtml");
}

另见this answer