spring security + primefaces自定义登录

时间:2015-10-28 03:51:49

标签: java spring primefaces spring-security

我正在尝试使用注释将spring security 4.0.2与primefaces 5.0集成在一起。 这是 web.xml

<context-param>
    <description>Configure ContextLoaderListener to use AnnotationConfigWebApplicationContext instead of the default XmlWebApplicationContext</description>
    <param-name>contextClass</param-name>
    <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>com.giong.config.ApplicationConfig</param-value>
</context-param>
<context-param>
    <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
    <param-value>.xhtml</param-value>
</context-param>
<context-param>
    <description>Spring Security Facelets Tag Library</description>
    <param-name>javax.faces.FACELETS_LIBRARIES</param-name>
    <param-value>classpath*:spring/spring-security.taglib.xml</param-value>
</context-param>
<context-param>
    <description>Project Stage Level</description>
    <param-name>javax.faces.PROJECT_STAGE</param-name>
    <!-- Change to "Production" when you are ready to deploy -->
    <param-value>Development</param-value>
</context-param>
<context-param>
    <description>State saving method: 'client' or 'server' (=default). See JSF Specification 2.5.2</description>
    <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
    <param-value>client</param-value>
</context-param>
<context-param>
    <param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
    <param-value>resources.application</param-value>
</context-param>
<context-param>
    <param-name>pimefaces.THEME</param-name>
    <param-value>dot-luv</param-value>
</context-param>
<!-- Spring Security -->
<filter>
    <description>Enable Spring Filter: Spring Security works on the concept of Filters</description>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <!-- Defines urls pattern on which the filter is applied -->
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>REQUEST</dispatcher>
    <!-- mandatory to allow the managed bean to forward the request to the filter -->
</filter-mapping>
<!-- Spring -->
<listener>
    <description>The Bootstrap listener to start up and shut down Spring's root WebApplicationContext. It is registered to Servlet Container</description>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<listener>
    <listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>
<servlet>
    <description>JSF Servlet is defined to container</description>
    <display-name>Faces Servlet</display-name>
    <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>
<welcome-file-list>
    <welcome-file>pages/index.xhtml</welcome-file>
</welcome-file-list>

弹簧安全配置文件

public class SecurityConfig extends WebSecurityConfigurerAdapter {


private final int TOKEN_VALIDITY_SECONDS = 60 * 60 * 24;

@Autowired
private DataSource dataSource;

@Autowired
private UserDetailsService userDetailsService;

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(this.userDetailsService).passwordEncoder(this.passwordEncoder());
}

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/javax.faces.resource/**", "/resources/**");
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    super.configure(http);

    // @formatter:off
    http
        .csrf().disable().httpBasic()
        .and()
            .headers().cacheControl().and()
        .and()
            .sessionManagement()
            .sessionFixation().none()
        .and()
            .authorizeRequests().anyRequest().authenticated()
        .and()
            .formLogin().loginPage("/pages/login.xhtml").permitAll()
        .and()
            .logout().invalidateHttpSession(true)
                     .deleteCookies("JSESSIONID", AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY)
                     .logoutSuccessUrl("/")
        .and()
            .rememberMe().tokenRepository(this.tokenRepository()).tokenValiditySeconds(this.TOKEN_VALIDITY_SECONDS);
    ;       
    // @formatter:on
}

@Override
@Bean(name = "authenticationManager")
public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
}

@Bean(name = "passwordEncoder")
public PasswordEncoder passwordEncoder() {
    final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    return passwordEncoder;
}

@Bean(name = "tokenRepository")
public PersistentTokenRepository tokenRepository() {
    final JdbcTokenRepositoryImpl db = new JdbcTokenRepositoryImpl();
    db.setDataSource(this.dataSource);
    return db;
}

}

登录页面

<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"
    xmlns:p="http://primefaces.org/ui">
<h:head>
    <title>#{i18n['login']}</title>
    <meta
        http-equiv="Content-Type"
        content="text/html; charset=UTF-8" />
    <h:outputStylesheet
        library="css"
        name="style.css" />
</h:head>
<h:body>
    <div align="center">
        <h1>#{i18n['info.welcome_to_leave_application']}</h1>
        <p:panel
            header="#{i18n['login']}"
            style="width: 480px">
            <p:growl
                showDetail="true"
                life="8000" />
            <h:form
                id="frmLogin"
                prependId="false">
                <div class="ui-grid ui-grid-responsive">
                    <div class="ui-grid-row value">
                        <div class="ui-grid-col-3 label">
                            <p:outputLabel
                                for="username"
                                value="#{i18n['username']}" />
                        </div>
                        <div class="ui-grid-col-6 value">
                            <p:inputText
                                id="username"
                                required="true"
                                requiredMessage="#{i18n['error.please_enter_username']}"
                                label="#{i18n['username']}" />
                        </div>
                    </div>

                    <div class="ui-grid-row value">
                        <div class="ui-grid-col-3 label">
                            <p:outputLabel
                                for="password"
                                value="#{i18n['password']} " />
                        </div>
                        <div class="ui-grid-col-6 value">
                            <p:password
                                id="password"
                                required="true"
                                requiredMessage="#{i18n['error.please_enter_password']}"
                                label="#{i18n['password']}" />
                        </div>
                    </div>

                    <div class="ui-grid-row value">
                        <div
                            class="ui-grid-col-4"
                            align="right">
                            <h:selectBooleanCheckbox
                                id="remember-me"
                                label="#{i18n['remember_me']}"
                                style="width: 20px;height: 20px;" />
                        </div>
                        <div
                            class="ui-grid-col-5"
                            align="left">
                            <p:outputLabel
                                for="remember-me"
                                value=" #{i18n['remember_me']}" />
                        </div>
                    </div>
                </div>

                <p:commandButton
                id="btnLogin"
                value="#{i18n['login']}"
                action="#{loginManagedBean.doLogin()}"
                icon="ui-icon-person"
                ajax="false" />

            </h:form>
        </p:panel>
    </div>
</h:body>
</html>

登录托管bean

@ManagedBean(name = "loginManagedBean")
@RequestScoped
public class LoginManagedBean extends AbtractManagedBean implements PhaseListener {

private static final long serialVersionUID = 1L;

/*
 ***************************************    ACTIONS     *************************************** 
 */

@Override
public void afterPhase(PhaseEvent event) {

}

@Override
public void beforePhase(PhaseEvent event) {
    final Exception e = (Exception) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get(WebAttributes.AUTHENTICATION_EXCEPTION);

    if (e instanceof BadCredentialsException) {
        e.printStackTrace();
        FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(WebAttributes.AUTHENTICATION_EXCEPTION, null);
        JSFMessageUtil.sendFatalMessageToUser(JSFMessageUtil.getResource("error.user_pass_is_invalid"), "");
    }
    else if (e instanceof LockedException || e instanceof DisabledException) {
        e.printStackTrace();
        FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(WebAttributes.AUTHENTICATION_EXCEPTION, null);
        JSFMessageUtil.sendErrorMessageToUser(JSFMessageUtil.getResource("error.user_acc_has_been_suspended"), "");
    }
}


@Override
public PhaseId getPhaseId() {
    return PhaseId.RENDER_RESPONSE;
}

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


/*
 ***************************************    GETTER & SETTER *************************************** 
 */

}

如果正确输入用户名/密码,我可以无任何错误登录。 但是有一些问题

  1. 当我忘记输入用户名/密码或输入无效值时,没有任何消息被提供。甚至控制台都没有显示任何内容。

  2. 我在LoginManagedBean.doLogin()中切换了断点,但它并没有在断点处停止。我甚至可以删除doLogin()方法的内容,但仍然以普通方式登录。我假设没有调用doLogin()方法,它对我当前的工具不是必需的。但如果我从

  3. 更改登录页面中的登录按钮
    <p:commandButton id="btnLogin" value="#{i18n['login']}" action="#{loginManagedBean.doLogin()}" icon="ui-icon-person" ajax="false" />
    

    <p:button value="#{loginManagedBean.doLogin()}">#{i18n['login']}</p:button>
    
    调用了

    doLogin()方法,但是有一个错误: HTTP Status 404 - /leave-application/login

    所以,在这种情况下我应该使用p:button还是p:commandButton;以及如何向用户显示身份验证例外?

0 个答案:

没有答案