我们使用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>
customUserDetailsService,按要求:
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;
}
}
答案 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;
}