【问题标题】:No bean named 'CustomAuthenticationProvider' is defined未定义名为“CustomAuthenticationProvider”的 bean
【发布时间】:2014-09-28 18:16:09
【问题描述】:

我正在尝试从工作的 jdbc-user-service 切换到实现 AuthenticationProvider 的 customAuthenticationProvider,但是 spring 没有找到它。我不确定这是否与将我的配置放在 xml 中或有什么问题有关。我从调度程序 servlet 中的一个开始,但是根据我阅读的内容的建议,我也在 spring-security.xml 中添加了一个,这没有任何区别。任何想法我的配置有什么问题?

谢谢!

mvc-dispatch-servlet.xml

 <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

    <context:component-scan base-package="com.mkyong.*" />
    <!-- Currently not working. Made a work around by having resources at /resources and pages at /pages -->
  <mvc:resources location="/resources/" mapping="/resources/" />

      <!-- also add the following beans to get rid of some exceptions -->
     <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
     <bean
      class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
     </bean>

    <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix"><value>/WEB-INF/pages/</value></property>
        <property name="suffix"><value>.jsp</value></property>
    </bean>

</beans>

spring-security.xml

<beans:beans xmlns="http://www.springframework.org/schema/security"
  xmlns:context="http://www.springframework.org/schema/context"  
    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-3.0.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-3.2.xsd>

    <!-- enable use-expressions -->
    <http auto-config="true" use-expressions="true">
        <!-- login page must be available to all. The order matters, if this is after something which secures the page this will fail. -->
        <intercept-url pattern="/pages/login" access="permitAll" />
        <intercept-url pattern="/pages/admin/**" access="hasRole('_admin')" />
        <intercept-url pattern="/pages/trade/**" access="hasRole('_trader')" />
        <intercept-url pattern="/pages/discover/**" access="hasRole('_users')" />       
        <!-- access denied page -->
        <access-denied-handler error-page="/pages/403" />
        <form-login 
            login-page="/pages/login" 
            default-target-url="/pages/trade/index" 
            authentication-failure-url="/login?error" 
            username-parameter="username"
            password-parameter="password" />
        <logout logout-url="/pages/logout" logout-success-url="/pages/login?logout" />
        <!-- enable csrf protection -->
        <csrf/>
    </http>

    <!-- Select users and user_roles from database -->
    <authentication-manager>
        <authentication-provider ref="CustomAuthenticationProvider"/>
        <!--<jdbc-user-service data-source-ref="dataSource"
                users-by-username-query=
                    "select email,pwhash, enabled from users where email=?"
                authorities-by-username-query=
                    "select email, groupname from usergroups where email =?  " /> 
        </authentication-provider> -->
    </authentication-manager>  
</beans:beans>

CustomAuthenticationProvider.java

package com.mkyong.web.controller;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component;

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

  @Override
  public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    User user = new User();
    user.name = authentication.getName();
    user.password = authentication.getCredentials().toString();
    try {
      user.id = Instance.users.getUserByEmail(user.name).getUserID();
    } catch (Exception e) {
      Instance.debug("CustomAuthenticationProvider authenticate","Error getting user" + e);
    }

    // use the credentials to try to authenticate against the third party system
    if (passVerify(user)) {
      List<GrantedAuthority> grantedAuths = new ArrayList<GrantedAuthority>();
      try {
        UserRoles roles = Instance.users.getUser(user.id).roles;
        userRolesToDatabaseRoles(roles, grantedAuths);
      } catch (Exception e) {
        Instance.debug("CustomAuthenticationProvider authenticate","Error getting user" + e);
      }
      return new UsernamePasswordAuthenticationToken(user.name, user.password, grantedAuths);
    } else {
      Instance.debug("CustomAuthenticationProvider authenticate","Unable to authenticate");
      return null;
    }
  }

  private void userRolesToDatabaseRoles(UserRoles roles, List<GrantedAuthority> grantedAuths) {
    if(roles.admin){
      grantedAuths.add(new SimpleGrantedAuthority("_admin"));
    }
    if(roles.trader){
      grantedAuths.add(new SimpleGrantedAuthority("_trader"));
    }
    if(roles.analyst){
      grantedAuths.add(new SimpleGrantedAuthority("_users"));
    }


  }

  private boolean passVerify(User user) {
    StringBuffer MD5 = getMD5(user);    
    try {
      //User still has an MD5 password, so change them over to bcrypt
      if(MD5.toString().equals(Instance.users.getPasswordHash(user.name))){
        String hashedPassword = getBcrypt(user).toString();
        instance.users.changePassword(user.id, hashedPassword);
        return true;
      }
    } catch (Exception e) {
      instance.debug("CustomAuthenticationProvider passVerify","Error getting userpassword" + e);
    }

    StringBuffer bcrypt = getBcrypt(user);

    if(bcrypt.toString().equals(user.password)){
      return true;
    }



    return false;
  }

  public StringBuffer getBcrypt(User user) {
    //This sets how many rounds bcrypt will run. The high the number the longer it takes which will slow down user login, however it also slows
    //down a would be attacker. This is a key advantage of bcrypt over other algorithms. *IMPORTANT* changing the strength will result in needing to 
    //rehash all passwords. This is very doable but requires more work. 
    //See http://crypto.stackexchange.com/questions/3003/do-i-have-to-recompute-all-hashes-if-i-change-the-work-factor-in-bcrypt
    BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(10);
    StringBuffer hashedPassword = new StringBuffer(); 
    hashedPassword.append(passwordEncoder.encode(user.password));

    return hashedPassword;
  }

  public StringBuffer getMD5(User user) {
    StringBuffer sb = null;
    MessageDigest md;

    String original = "a";
    try {
      md = MessageDigest.getInstance("MD5");
      md.update(original.getBytes());
      byte[] digest = md.digest();
      sb = new StringBuffer();
      for (byte b : digest) {
        sb.append(String.format("%02x", b & 0xff));
      }

    } catch (NoSuchAlgorithmException e) {
     instance.debug("CustomAuthenticationProvider hashMD5","Error getting MD5 instance" + e);
    }

    return sb;
  }


  @Override
  public boolean supports(Class<?> authentication) {
    return authentication.equals(UsernamePasswordAuthenticationToken.class);
  }

  public class User{
    public long id;
    protected String name, password;
  }



}

不确定是否需要发布 web.xml,但这里是:

web.xml

<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">


        <!-- Spring MVC -->
    <servlet>
        <servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

      <servlet>
    <servlet-name>InitServlet</servlet-name>
    <servlet-class>servletInitServlet</servlet-class>
    <init-param>
      <param-name>configfile</param-name>
      <param-value>C:/transmetric/dev/java/WebContent/WEB-INF/config.properties</param-value>
    </init-param>
    <load-on-startup>2</load-on-startup>
  </servlet>

  <servlet>
    <servlet-name>AdminServlet</servlet-name>
    <servlet-class>servlet.admin</servlet-class>
    <load-on-startup>3</load-on-startup>
  </servlet>

  <servlet>
    <servlet-name>UserServlet</servlet-name>
    <servlet-class>servlet.user</servlet-class>
    <load-on-startup>4</load-on-startup>
  </servlet>

  <servlet>
    <servlet-name>SignupUserServlet</servlet-name>
    <servlet-class>servlet.user.SignupUserServlet</servlet-class>
    <load-on-startup>5</load-on-startup>
  </servlet>

  <servlet>
   <servlet-name>ReceiveFile</servlet-name>
    <servlet-class>servlet.user</servlet-class>
    <load-on-startup>6</load-on-startup>
  </servlet>

  <servlet-mapping>
        <servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>/pages/*</url-pattern>
    </servlet-mapping>

  <servlet-mapping>
   <servlet-name>AdminServlet</servlet-name>
   <url-pattern>/AdminServlet</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
   <servlet-name>UserServlet</servlet-name>
   <url-pattern>/UserServlet</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
   <servlet-name>SignupUserServlet</servlet-name>
   <url-pattern>/SignupUserServlet</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
   <servlet-name>ReceiveFile</servlet-name>
   <url-pattern>/ReceiveFile</url-pattern>
  </servlet-mapping>

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

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

    <!-- Spring Security -->
    <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>
    </filter-mapping>

</web-app>

【问题讨论】:

    标签: java xml spring spring-mvc spring-security


    【解决方案1】:

    尝试在 spring-security xml 中定义您的 CustomAuthenticationProvider bean,而不是使用 @Component 注释。

    或者您也可以尝试将&lt;context:component-scan base-package="com.mkyong.*" /&gt; 放入您的安全 xml 中

    【讨论】:

    • 感谢您和@Andrei,这似乎是没有 和大写字母的组合。我已经单独尝试过,但是当错误没有改变时,我想我从来没有一起尝试过。既然你先回答了,我想我会计算你的答案,但两者都有同样的帮助。谢谢这真的有帮助!
    【解决方案2】:

    改变

    <authentication-provider ref="CustomAuthenticationProvider"/>
    

    to(不是未大写的 bean 名称)

    <authentication-provider ref="customAuthenticationProvider"/>
    

    默认情况下,带有@Component 注释的自动检测组件的bean 名称是未大写的非限定类名称。在您的情况下,这将是 customAuthenticationProvider

    【讨论】:

      【解决方案3】:

      在我的情况下,由于 Maven 构建错误,实际上缺少 .class 文件导致异常:

      • (YourApp)/target/classes
      • (YourApp)/target/(YourApp).war/WEB-INF/classes/
      • (YourApp)/target/(YourApp).war/WEB-INF/lib/

      根本原因是 Eclipse 问题:它切换到使用嵌入式 Maven,而我总是使用外部的。要修复它,我必须:

      1. 首选项 > Maven > 安装,设置外部 Maven
      2. 从工作区中删除项目
      3. 删除项目文件夹中的所有派生文件/文件夹(target/bin/.settings/.classpath.project),只保留pom.xmlsrc/
      4. 文件 > 导入... > 现有 Maven 项目,选择我的项目。

      重建后,所有必需的类都在那里。

      【讨论】:

        猜你喜欢
        • 2018-05-25
        • 2017-10-09
        • 1970-01-01
        • 1970-01-01
        • 2015-05-05
        • 2012-08-20
        • 2016-01-02
        • 2015-04-21
        • 2012-03-25
        相关资源
        最近更新 更多