为什么我收到以下错误? "没有定义类型的唯一bean:期望的单个匹配bean但找到了3"

时间:2014-10-10 20:42:12

标签: java eclipse ant spring-security

我们使用Eclipse Kepler IDE开发我们的GWT应用程序,并且已经使用Ant脚本长时间部署到Tomcat容器。我们最近决定转而使用Hudson CI服务器来简化GWT编译和部署过程。我们遇到的问题是,当我们允许Eclipse执行自己的连续构建时,然后执行GWT编译/部署,我们的应用程序按预期工作。但是,当我们使用外部javac进程进行编译时,无论是从独立的JDK还是使用Eclipse的编译器(org.eclipse.jdt.core.JDTCompilerAdapter),我们都会收到以下错误消息:

Error creating bean with name 'loginServiceImpl' defined in file [/opt/tomcat/webapps/ROOT##10616/WEB-INF/classes/com/company/ribeye/server/service/LoginServiceImpl.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [org.springframework.security.authentication.AuthenticationManager]: : No unique bean of type [org.springframework.security.authentication.AuthenticationManager] is defined: expected single matching bean but found 3: [org.springframework.security.config.authentication.AuthenticationManagerFactoryBean#0, org.springframework.security.authentication.ProviderManager#0, org.springframework.security.authenticationManager]; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [org.springframework.security.authentication.AuthenticationManager] is defined: expected single matching bean but found 3: [org.springframework.security.config.authentication.AuthenticationManagerFactoryBean#0, org.springframework.security.authentication.ProviderManager#0, org.springframework.security.authenticationManager]

我们没有使用任何类型的依赖项管理器,但Eclipse似乎没有问题地处理java编译,我们没有遇到此错误。我想强调这个错误只发生在我们使用Ant任务和javac进行编译时。同样,即使使用Eclipse自己的捆绑编译器,我们也遇到了问题。我还想补充一点,我不是Java开发人员,但我是开发团队的DevOps经理,因此CI服务器和部署策略属于我的域。我有一点Java知识,我还在学习,所以如果这非常简单,我会事先道歉。

这是我的相关代码(为了简洁起见,并未列出所有导入的代码):

package com.company.ribeye.server.service;


import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;

@Controller
@RequestMapping("/login")
public class LoginServiceImpl extends GWTController implements LoginService {

    private static final long serialVersionUID = 1L;
    private final AuthenticationManager authenticationManager;
    private final UserDao userDao;
    private final UserPreferenceDao userPreferenceDao;

    @Autowired
    public LoginServiceImpl(AuthenticationManager authenticationManager, UserDao userDao, UserPreferenceDao userPreferenceDao) {
        this.authenticationManager = authenticationManager;
        this.userDao = userDao;
        this.userPreferenceDao = userPreferenceDao;
    }

    @Override
    public ApplicationData getApplicationData() {
        ApplicationData ap = new ApplicationData();
        SimpleDateFormat df = new SimpleDateFormat("yyyy");
        ap.setCurrentYear(Integer.parseInt(df.format(new Date())));
        ap.setLoggedIn(false);

        if (!ServerContext.isProductionServer() && ServerContext.isDevServer()) {
            Pair<String, String> login = ServerContext.getDevAutoLogin();
            ap.setDevModeAutoUsername(login.getA());
            ap.setDevModeAutoPassword(login.getB());
        }

        if (ServerContext.getSession().getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY) == null) {
            return ap;
        }

        User user = ServerContext.getCurrentUser();

        if (user == null) {
            return ap;
        }
        ApplicationContext ctx = ServerContext.getApplicationContext();

        if (user.isPortalUser()) {
            CustomerDao customerDao = (CustomerDao) ctx.getBean("customerDaoImpl");
            user.setCustomer(customerDao.getById(user.getCustomerId()));
        } else if (user.isVendorUser()) {
            VendorDao vendorDao = (VendorDao) ctx.getBean("vendorDaoImpl");
            user.setVendor(vendorDao.getById(user.getVendorId()));
        }

        ap.setLoggedIn(true);
        ap.setDashDatabaseConnection(DashDataSourceContextHolder.getDatabaseType());
        ap.setBuildNumber(ServerContext.getBuildNumber());
        ap.setBuildDate(ServerContext.getBuildDate());
        ap.setNextReleaseDate(ServerContext.getNextReleaseDate());
        ap.setCurrentUser(user);
        ap.setUserLinks(userPreferenceDao.getUserLinks(user.getId()));
        ap.setMyContacts(userPreferenceDao.getMyContacts());
        if (!user.isSwitched()) {
            UserDaoImpl.updateUserActivity(user.getId());
        }
        ap.setUserActivity(UserDaoImpl.getAllUserActivity());

        SystemDao systemDao = (SystemDao) ctx.getBean("systemDaoImpl");
        ap.setEntityLinkers(systemDao.getEntityLinkers());
        PollUpdateData pud = new PollUpdateData(user.getId());
        ap.setNotificationSummary(systemDao.getPollData(pud).getNotificationSummary());
        ap.setNotificationEntityTypeColors(systemDao.getNotificationEntityTypeColors());
        ap.setUserPreferences(userPreferenceDao.getPreferencesByGroupName(user.getId(), null));

        ArgMap<FlagArg> flagArgs = new ArgMap<FlagArg>();
        flagArgs.put(FlagArg.USER_ID, user.getId());
        ap.setFlagDefinitions(Common.asArrayList(userPreferenceDao.getFlagDefinitions(flagArgs)));

        DocumentDao documentDao = (DocumentDao) ctx.getBean("documentDaoImpl");
        ap.setLogoImage(documentDao.getLogoImage());

        return ap;
    }

以下是applicationContext-security.xml的相关部分:

<authentication-manager alias="authenticationManager">
    <authentication-provider ref="ldapAuthProvider" />
    <authentication-provider user-service-ref="customUserDetailsService">
        <password-encoder ref="passwordEncoder">
            <salt-source ref="saltSource" />
        </password-encoder>
    </authentication-provider>
</authentication-manager>


<beans:bean id="ldapAuthProvider" class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
<beans:constructor-arg>
    <beans:bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
    <beans:constructor-arg ref="contextSource" />
    <beans:property name="userSearch">
        <beans:bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
            <beans:constructor-arg index="0" value="" />
            <beans:constructor-arg index="1" value="REDACTED" />
            <beans:constructor-arg index="2" ref="contextSource" />
        </beans:bean>
    </beans:property>
    </beans:bean>
</beans:constructor-arg>

<beans:constructor-arg>
    <beans:bean class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
         <beans:constructor-arg ref="contextSource"/>
         <beans:constructor-arg value="REDACTED" />
         <beans:property name="groupRoleAttribute" value="cn" />
         <beans:property name="searchSubtree" value="false" />
         <beans:property name="convertToUpperCase" value="true" />
         <beans:property name="rolePrefix" value="ROLE_" />
         <beans:property name="groupSearchFilter" value="member={0}" />
         <beans:property name="defaultRole" value="ROLE_DASH" />
    </beans:bean>
</beans:constructor-arg>

和dispatcher-servlet.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:context="http://www.springframework.org/schema/context"
       xmlns:security="http://www.springframework.org/schema/security"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
       http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">

  <context:component-scan base-package="com.company.ribeye.server.service" />
  <context:component-scan base-package="com.company.ribeye.server.dao" />
  <context:component-scan base-package="com.company.ribeye.server.util" />
  <context:annotation-config />
  <security:global-method-security pre-post-annotations="enabled" />
</beans>

customUserDetailsS​​ervice,按要求:

package com.company.ribeye.server.spring;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
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;

public class CustomUserDetailsService implements UserDetailsService {
    private DataSource dataSource;
    private JdbcTemplate sjt;

    public DataSource getDataSource() {
        return dataSource;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        RowMapper<User> mapper = new RowMapper<User>() {
            @Override
            public User mapRow(ResultSet rs, int rowNum) throws SQLException {

                return new User(rs.getString("Login"), rs.getString("PasswordDigest"), rs.getBoolean("IsEnabled"), rs.getBoolean("IsEnabled"), true, true,
                        getAuthorities(rs));
            }
        };

        User user;

        String sql = "select top 1 u.ID, u.Login, u.PasswordDigest, u.CustomerID, u.VendorID, u.IsPortalSuperUser, ";
        sql += "dbo.IsActive(u.StartDate, u.EndDate, getdate()) as IsEnabled from Users u ";
        sql += "where u.Login = ? and PasswordDigest is not null";

        try {
            user = sjt.queryForObject(sql, mapper, username);
        } catch (DataAccessException e) {
            throw new UsernameNotFoundException(username);
        }

        return user;
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
        sjt = new JdbcTemplate(dataSource);
    }

    private List<GrantedAuthority> getAuthorities(ResultSet rs) throws SQLException {
        final List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>();

        if (rs.getInt("VendorID") > 0) {
            authList.add(new SimpleGrantedAuthority("ROLE_COMPANY_DASH_USERS"));
            return authList;
        }
        authList.add(new SimpleGrantedAuthority("ROLE_PORTAL_USER"));
        if (rs.getBoolean("IsPortalSuperUser")) {
            authList.add(new SimpleGrantedAuthority("ROLE_PORTAL_SUPERUSER"));
            authList.add(new SimpleGrantedAuthority("ROLE_PORTAL_BILLING"));
            authList.add(new SimpleGrantedAuthority("ROLE_PORTAL_OPERATIONS"));
            return authList;
        }

        // if not a superuser, fetch account-level roles from database
        RowMapper<List<GrantedAuthority>> mapper = new RowMapper<List<GrantedAuthority>>() {
            @Override
            public List<GrantedAuthority> mapRow(ResultSet rs, int rowNum) throws SQLException {
                if (rs.getInt("Billing") > 0) {
                    authList.add(new SimpleGrantedAuthority("ROLE_PORTAL_BILLING"));
                }
                if (rs.getInt("Operations") > 0) {
                    authList.add(new SimpleGrantedAuthority("ROLE_PORTAL_OPERATIONS"));
                }

                return authList;
            }
        };
        String sql = "select sum(cast(Billing as int)) as Billing, sum(cast(Operations as int)) as Operations ";
        sql += "from PortalUserRoles ";
        sql += "where UserID = ?";
        sjt.queryForObject(sql, mapper, rs.getInt("ID"));

        return authList;
    }
}

1 个答案:

答案 0 :(得分:1)

经过多次搜索,我找到了解决方案,由#spring(freenode)的某个人给我。我仍然不知道为什么这不是Eclipse内部的问题,但至少它现在正在工作。

虽然我无法在我们的应用程序中找到正在创建其他两个bean的地方,但是向LoginServiceImpl添加@Qualifier("authenticationManager")注释解决了这个问题:

@Autowired
    public LoginServiceImpl(@Qualifier("authenticationManager") AuthenticationManager authenticationManager, UserDao userDao,
            UserPreferenceDao userPreferenceDao) {
        this.authenticationManager = authenticationManager;
        this.userDao = userDao;
        this.userPreferenceDao = userPreferenceDao;
    }