spring security 用户名密码错误返回401页面

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring security 用户名密码错误返回401页面相关的知识,希望对你有一定的参考价值。

   因为要在登陆的时候增加企业编号验证,自己定义了DisUsernamePasswordAuthenticationFilter类并继承AbstractAuthenticationProcessingFilter这个类,但是运行后发现只要用户名密码错误或者没有权限等其他错误都返回401 -Authentication Failed,如下图:

技术分享

    后经过排查发现,在重写AbstractAuthenticationProcessingFilter类时没有传入登录失败跳转的路径failureUrl.找到问题后我在AbstractAuthenticationProcessingFilter发现该类定义了AuthenticationSuccessHandler和AuthenticationFailureHandler,所以我们可以在application-security.xml中定义一下代码:

    

<beans:bean id="simpleUrlAuthenticationFailureHandler"  
        class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFai            lureHandler">  
        <!-- 可以配置相应的跳转方式。属性forwardToDestination为true采用forward false为sen            dRedirect -->  
        <beans:property name="defaultFailureUrl" value="/login.jsp?auth-failure=true"></b                eans:property>  
</beans:bean>

    并在自定义的DisUsernamePasswordAuthenticationFilter类中引入

    

  <!-- 登录处理Filter  -->  
    <beans:bean id="loginProcessFilter" class="com.fpi.safety.common.security.DisUsername        PasswordAuthenticationFilter">  
        <beans:property name="companyCode" value="companyCode" />  
        <beans:property name="usernameParameter" value="username" />    
        <beans:property name="passwordParameter" value="password" />  
        <!-- 登陆失败处理类 -->
        <beans:property name="simpleUrlAuthenticationFailureHandler" ref="simpleUrlAuthen            ticationFailureHandler" /> 
        <beans:property name="authenticationSuccessHandler" ref="appSessionSuccessHandler        " />  
        <beans:property name="authenticationManager" ref="disuserAuthManager" /> 
    </beans:bean>


    DisUsernamePasswordAuthenticationFilter.java

    

public class DisUsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter  {
	
	

    public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "j_username";
    public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "j_password";
    public static final String SPRING_SECURITY_FORM_COMPANY_CODE_KEY = "company_code";
    public static final String USERNAME_LOGINID_SPLIT = "-"; 
   
    /**
     * @deprecated If you want to retain the username, cache it in a customized {@code AuthenticationFailureHandler}
     */
    @Deprecated
    public static final String SPRING_SECURITY_LAST_USERNAME_KEY = "SPRING_SECURITY_LAST_USERNAME";

    private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;
    private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;
    private String companyCode = SPRING_SECURITY_FORM_COMPANY_CODE_KEY;
    private SimpleUrlAuthenticationFailureHandler simpleUrlAuthenticationFailureHandler;
    
    private boolean postOnly = true;

    //~ Constructors ===================================================================================================

    public DisUsernamePasswordAuthenticationFilter() {
        super("/j_spring_security_check");
    }

    //~ Methods ========================================================================================================

    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }

        String username = obtainUsername(request);
        String password = obtainPassword(request);
        String companyCode = obtainCompanyCode(request);
        
        if (username == null) {
            username = "";
        }

        if (password == null) {
            password = "";
        }
        
        if(companyCode == null || companyCode.equals("")){
        	companyCode = "null";
        }
       
        username = username.trim();
        companyCode =  companyCode.trim();
        
        username = username+USERNAME_LOGINID_SPLIT+companyCode;
        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);

        // Allow subclasses to set the "details" property
        setDetails(request, authRequest);

        return this.getAuthenticationManager().authenticate(authRequest);
    }

    
    protected String obtainCompanyCode(HttpServletRequest request) {
        return request.getParameter(companyCode);
    }
    /**
     * Enables subclasses to override the composition of the password, such as by including additional values
     * and a separator.<p>This might be used for example if a postcode/zipcode was required in addition to the
     * password. A delimiter such as a pipe (|) should be used to separate the password and extended value(s). The
     * <code>AuthenticationDao</code> will need to generate the expected password in a corresponding manner.</p>
     *
     * @param request so that request attributes can be retrieved
     *
     * @return the password that will be presented in the <code>Authentication</code> request token to the
     *         <code>AuthenticationManager</code>
     */
    protected String obtainPassword(HttpServletRequest request) {
        return request.getParameter(passwordParameter);
    }

    /**
     * Enables subclasses to override the composition of the username, such as by including additional values
     * and a separator.
     *
     * @param request so that request attributes can be retrieved
     *
     * @return the username that will be presented in the <code>Authentication</code> request token to the
     *         <code>AuthenticationManager</code>
     */
    protected String obtainUsername(HttpServletRequest request) {
        return request.getParameter(usernameParameter);
    }

    /**
     * Provided so that subclasses may configure what is put into the authentication request‘s details
     * property.
     *
     * @param request that an authentication request is being created for
     * @param authRequest the authentication request object that should have its details set
     */
    protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
    }

    /**
     * Sets the parameter name which will be used to obtain the username from the login request.
     *
     * @param usernameParameter the parameter name. Defaults to "j_username".
     */
    public void setUsernameParameter(String usernameParameter) {
        Assert.hasText(usernameParameter, "Username parameter must not be empty or null");
        this.usernameParameter = usernameParameter;
    }

    /**
     * Sets the parameter name which will be used to obtain the password from the login request..
     *
     * @param passwordParameter the parameter name. Defaults to "j_password".
     */
    public void setPasswordParameter(String passwordParameter) {
        Assert.hasText(passwordParameter, "Password parameter must not be empty or null");
        this.passwordParameter = passwordParameter;
    }
    
    
    @Override
    public void afterPropertiesSet() {
    	super.afterPropertiesSet();
    	/* 
         *该处理器实现了 AuthenticationFailureHandler 
         *用于处理登录失败后,跳转的界面 
         */  
    	this.setAuthenticationFailureHandler(simpleUrlAuthenticationFailureHandler);
    }
    
    
    /**
     * Defines whether only HTTP POST requests will be allowed by this filter.
     * If set to true, and an authentication request is received which is not a POST request, an exception will
     * be raised immediately and authentication will not be attempted. The <tt>unsuccessfulAuthentication()</tt> method
     * will be called as if handling a failed authentication.
     * <p>
     * Defaults to <tt>true</tt> but may be overridden by subclasses.
     */
    public void setPostOnly(boolean postOnly) {
        this.postOnly = postOnly;
    }

    public final String getUsernameParameter() {
        return usernameParameter;
    }

    public final String getPasswordParameter() {
        return passwordParameter;
    }

	public String getCompanyCode() {
		return companyCode;
	}

	public void setCompanyCode(String companyCode) {
		this.companyCode = companyCode;
	}

	public SimpleUrlAuthenticationFailureHandler getSimpleUrlAuthenticationFailureHandler() {
		return simpleUrlAuthenticationFailureHandler;
	}

	public void setSimpleUrlAuthenticationFailureHandler(
			SimpleUrlAuthenticationFailureHandler simpleUrlAuthenticationFailureHandler) {
		this.simpleUrlAuthenticationFailureHandler = simpleUrlAuthenticationFailureHandler;
	}
    
    
}

    这样就能使登陆错误成功返回登陆页面,问题得以解决。

本文出自 “13085720” 博客,请务必保留此出处http://13095720.blog.51cto.com/13085720/1968316

以上是关于spring security 用户名密码错误返回401页面的主要内容,如果未能解决你的问题,请参考以下文章

通过 Spring Security 的 Active Directory 身份验证返回由 LDAP 引起的有效用户的错误凭据:错误代码 49

返回用户名和密码以登录表单grails spring security

通过spring security进行的Active Directory身份验证会返回由LDAP引起的有效用户的错误凭据:错误代码49

java spring security,如果登录用户被禁用,如何知道密码是不是错误

Spring Security应用开发(09)密码错误次数限制

认证开发+Oauth2(授权码)模式+Spring Security+网关解说