Java 如何配置 Spring-Security 以访问数据库中的用户详细信息?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31965252/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to configure Spring-Security to access user details in database?
提问by Daniel Newtown
I am puzzled with SpringSecurity. There are many ways to implement a simple thing and I mixed them all up.
我对 SpringSecurity 感到困惑。有很多方法可以实现一个简单的事情,我把它们混合在一起。
My code is as follows but it throws exception. If I remove UserDetailsService
related codes, the application runs and I can login in-memory
users. As suggested below, I converted the configuration to XML based but users cannot sign-in.
我的代码如下,但它抛出异常。如果我删除UserDetailsService
相关代码,应用程序就会运行并且我可以登录in-memory
用户。如下所示,我将配置转换为基于 XML 的配置,但用户无法登录。
org.springframework.beans.factory.BeanCreationException: Error creating bean
with name 'securityConfig': Injection of autowired dependencies failed; nested
exception is org.springframework.beans.factory.BeanCreationException: Could
not autowire field:
org.springframework.security.core.userdetails.UserDetailsService
com.myproj.config.SecurityConfig.userDetailsService; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying
bean of type
[org.springframework.security.core.userdetails.UserDetailsService] found for
dependency: expected at least 1 bean which qualifies as autowire candidate for
this dependency. Dependency annotations:
{@org.springframework.beans.factory.annotation.Autowired(required=true),
@org.springframework.beans.factory.annotation.Qualifier(value=userDetailsService)}
Caused by: org.springframework.beans.factory.BeanCreationException: Could not
autowire field
org.springframework.security.core.userdetails.UserDetailsService
com.myproj.config.SecurityConfig.userDetailsService; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type
[org.springframework.security.core.userdetails.UserDetailsService]
found for dependency: expected at least 1 bean which qualifies as autowire
candidate for this dependency. Dependency annotations:
{@org.springframework.beans.factory.annotation.Autowired(required=true),
@org.springframework.beans.factory.annotation.Qualifier(value=userDetailsService)}
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type
[org.springframework.security.core.userdetails.UserDetailsService] found for
dependency: expected at least 1 bean which qualifies as autowire candidate for
this dependency. Dependency annotations:
{@org.springframework.beans.factory.annotation.Autowired(required=true),
@org.springframework.beans.factory.annotation.Qualifier(value=userDetailsService)}
Web.xml
网页.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<listener>
<listener-class>org.apache.tiles.extras.complete.CompleteAutoloadTilesListener</listener-class>
</listener>
<servlet>
<servlet-name>proj</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>proj</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
MvcWebApplicationInitializer
MvcWebApplicationInitializer
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class MvcWebApplicationInitializer
extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { SecurityConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
SecurityWebApplicationInitializer
SecurityWebApplicationInitializer
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
}
SecurityConfig
安全配置
@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("userDetailsService")
UserDetailsService userDetailsService;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(
passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/resources/**", "/", "/index", "/aboutus")
.permitAll()
.antMatchers("/profile/**")
.hasRole("USER")
.and()
.formLogin().loginPage("/signin").failureUrl("/signin?error")
.permitAll().and().logout().logoutUrl("/signout").permitAll();
}
@Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder;
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception
{
return super.authenticationManagerBean();
}
}
MemberServiceImpl
会员服务实现
@Service("userDetailsService")
public class MemberServiceImpl implements UserDetailsService {
@Autowired
MemberRepository memberRepository;
private List<GrantedAuthority> buildUserAuthority(String role) {
Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();
setAuths.add(new SimpleGrantedAuthority(role));
List<GrantedAuthority> result = new ArrayList<GrantedAuthority>(
setAuths);
return result;
}
private User buildUserForAuthentication(Member member,
List<GrantedAuthority> authorities) {
return new User(member.getEmail(), member.getPassword(),
member.isEnabled(), true, true, true, authorities);
}
@Override
@Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
Member member = memberRepository.findByUserName(username);
List<GrantedAuthority> authorities = buildUserAuthority("Role");
return buildUserForAuthentication(member, authorities);
}
}
Update 1
更新 1
Even after adding following annotation, and authenticationManagerBean
method from SecurityConfig the same exception is being thrown.
即使在添加以下注释和authenticationManagerBean
来自 SecurityConfig 的方法之后,也会抛出相同的异常。
@EnableGlobalMethodSecurity(prePostEnabled = true)
Update 2
更新 2
As suggested in one of the answers, I converted it to XML based configuration, the current code is as following;however, when I submit login form it does not do anything.
正如其中一个答案中所建议的那样,我将其转换为基于 XML 的配置,当前代码如下;但是,当我提交登录表单时,它什么也没做。
Spring-Security.xml
Spring-Security.xml
<beans:beans xmlns="http://www.springframework.org/schema/security"
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.0.xsd">
<beans:import resource='login-service.xml' />
<http auto-config="true" access-denied-page="/notFound.jsp"
use-expressions="true">
<intercept-url pattern="/" access="permitAll" />
<form-login login-page="/signin" authentication-failure-url="/signin?error=1"
default-target-url="/index" />
<remember-me />
<logout logout-success-url="/index.jsp" />
</http>
<authentication-manager>
<authentication-provider>
<!-- <user-service> <user name="admin" password="secret" authorities="ROLE_ADMIN"/>
<user name="user" password="secret" authorities="ROLE_USER"/> </user-service> -->
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="
select username,password,enabled
from Member where username=?"
authorities-by-username-query="
select username
from Member where username = ?" />
</authentication-provider>
</authentication-manager>
</beans:beans>
login-service.xml
登录服务.xml
<beans xmlns="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">
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/testProject" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
</beans>
回答by Charnjeet Singh
I think you forget for add this annotation on SecurityConfig Class
我认为您忘记在 SecurityConfig 类上添加此注释
@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("userDetailsService")
UserDetailsService userDetailsService;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(
passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/resources/**", "/", "/index", "/aboutus")
.permitAll().antMatchers("/profile/**").hasRole("USER").and()
.formLogin().loginPage("/signin").failureUrl("/signin?error")
.permitAll().and().logout().logoutUrl("/signout").permitAll();
}
@Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder;
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
and one things more I thinks this bean is not need
还有一件事我认为这个豆子是不需要的
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
Please try this hope this will work for you..
请试试这个希望这对你有用..
For get current user
获取当前用户
public String getUsername() {
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
if (authentication == null)
return null;
Object principal = authentication.getPrincipal();
if (principal instanceof UserDetails) {
return ((UserDetails) principal).getUsername();
} else {
return principal.toString();
}
}
public User getCurrentUser() {
if (overridenCurrentUser != null) {
return overridenCurrentUser;
}
User user = userRepository.findByUsername(getUsername());
if (user == null)
return user;
}
Thanks
谢谢
回答by The Student Soul
I think the issue could be due to missing @ComponentScan
annotation. When trying to autowire userDetailsService
in SecurityConfig
, it's not able to find a suitable bean to autowire with.
我认为这个问题可能是由于缺少@ComponentScan
注释。尝试在 中自动装配userDetailsService
时SecurityConfig
,无法找到合适的 bean 进行自动装配。
A spring application usually has a separate "application context", in addition to "mvc context", "security context" (which you already have via SecurityConfig
), etc.
除了“mvc 上下文”、“安全上下文”(您已经通过SecurityConfig
)等之外,spring 应用程序通常具有单独的“应用程序上下文” 。
I'm not sure if putting @ComponentScan
on SecurityConfig
itself will work on not, but you can give it a try:
我不确定穿上@ComponentScan
它SecurityConfig
自己是否会起作用,但您可以尝试一下:
@Configuration
@ComponentScan("your_base_package_name_here")
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...
}
Replace "your_base_package_name_here" with the name of the package containing your @Component
or @Service
classes.
将“your_base_package_name_here”替换为包含您的@Component
或@Service
类的包的名称。
If this doesn't work, add a new, empty class with @ComponentScan
annotation:
如果这不起作用,请添加一个带有@ComponentScan
注释的新的空类:
@Configuration
@ComponentScan("your_base_package_name_here")
public class AppConfig {
// Blank
}
Source: http://docs.spring.io/spring-javaconfig/docs/1.0.0.M4/reference/html/ch06s02.html
来源:http: //docs.spring.io/spring-javaconfig/docs/1.0.0.M4/reference/html/ch06s02.html
回答by Pramod Gaikwad
Spring cannot find the bean with qualifier userDetailsService
.
I think you should check your applicationContext.xml
file in case if you have forgot to configure UserDetailsService
's bean for Spring Security.If it there then try once by removing @Qualifier("userDetailsService")
.
Spring 找不到带有 qualifier 的 bean userDetailsService
。applicationContext.xml
如果您忘记UserDetailsService
为 Spring Security配置bean,我认为您应该检查您的文件。如果存在,则通过删除@Qualifier("userDetailsService")
.
follow this link. context.xml file configured against spring security
按照这个链接。 针对 spring 安全性配置的 context.xml 文件
回答by Jorge Jiménez Barra
Try changing the field type:
尝试更改字段类型:
@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("userDetailsService")
MemberServiceImpl userDetailsService;
回答by MS Ibrahim
See there are some errors exist in your code base try to resolve it by seeing the code below.
看到您的代码库中存在一些错误,请尝试通过查看下面的代码来解决它。
Remove your SecurityConfig file and convert into xml file based configuration.
删除您的 SecurityConfig 文件并转换为基于 xml 文件的配置。
Your spring-security.xml should look like this.
您的 spring-security.xml 应如下所示。
<security:http auto-config="true" >
<security:intercept-url pattern="/index*" access="ROLE_USER" />
<security:form-login login-page="/login" default-target-url="/index"
authentication-failure-url="/fail2login" />
<security:logout logout-success-url="/logout" />
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<!-- <security:user-service>
<security:user name="samplename" password="sweety" authorities="ROLE_USER" />
</security:user-service> -->
<security:jdbc-user-service data-source-ref="dataSource"
users-by-username-query="select username, password, active from users where username=?"
authorities-by-username-query="select us.username, ur.authority from users us, user_roles ur
where us.user_id = ur.user_id and us.username =? "
/>
</security:authentication-provider>
</security:authentication-manager>
web.xml should be looking like this:
web.xml 应该是这样的:
<servlet>
<servlet-name>sdnext</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>sdnext</servlet-name>
<url-pattern>/</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/sdnext-*.xml,
</param-value>
</context-param>
<welcome-file-list>
<welcome-file>index</welcome-file>
</welcome-file-list>
<!-- 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>
回答by sanastasiadis
It seams that your "userDetailsService" bean is declared @Autowired, but it's not available as a class (MemberServiceImpl) in the context of your SecurityConfig.
看来您的“userDetailsService”bean 被声明为@Autowired,但它在您的SecurityConfig上下文中不能作为类(MemberServiceImpl)使用。
I suppose in your MvcWebApplicationInitializeryou should include MemberServiceImplalso like:
我想在你的MvcWebApplicationInitializer你应该包括MemberServiceImpl也喜欢:
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { SecurityConfig.class, MemberServiceImpl.class };
}
回答by Phash
I am using Wicket and ran into the same problem. I could solve this problem by changeing the order in my AppInit Class to scan the package first, then register the calling Bean
我正在使用 Wicket 并遇到了同样的问题。我可以通过改变我的 AppInit 类中的顺序来解决这个问题,先扫描包,然后注册调用 Bean
public class AppInit implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException
{
// Create webapp context
AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext();
root.scan("my_package");
root.register(SpringSecurityConfiguration.class);
...#
}
回答by fjmodi
Try adding the following method to your SecurityConfig:
尝试将以下方法添加到您的 SecurityConfig:
@Bean
public UserDetailsService userDetailsServiceBean() throws Exception {
return super.userDetailsServiceBean();
}
回答by Pavan
Here is the answer , using the proper @ComponentScan will resolve, below is sample code snippet I am pasting which I also faced the same problem and resolved. Below is solved and works for issue related to bean creation exception for org.springframework.security.core.userdetails.UserDetailsService
这是答案,使用正确的@ComponentScan 将解决,下面是我粘贴的示例代码片段,我也遇到了同样的问题并已解决。以下已解决并适用于与org.springframework.security.core.userdetails.UserDetailsService 的bean 创建异常相关的问题
Step1:Write the Security Application Configuration class
Step1:编写安全应用配置类
import org.springframework.security.core.userdetails.UserDetailsService;
@Configuration
@EnableWebSecurity
public class LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("userDetailsServiceImpl")
UserDetailsService userDetailsService;
Here @ComponentScan is not mandatory in LoginSecurityConfig, you can define @ComponentScan in the root config class like below and import the LoginSecurityConfig.classLoginSecurityConfig.
这里 @ComponentScan 在LoginSecurityConfig 中不是强制性的 ,您可以像下面这样在根配置类中定义 @ComponentScan 并导入LoginSecurityConfig.classLoginSecurityConfig。
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "com.example" })
@Import(value = { LoginSecurityConfig.class })
public class LoginApplicationConfig
Step2:Now Autowiring the SpringBean org.springframework.security.core.userdetails.UserDetailsService
步骤 2:现在自动装配 SpringBean org.springframework.security.core.userdetails.UserDetailsService
@Service("userDetailsServiceImpl")
public class UserDetailsServiceImpl implements org.springframework.security.core.userdetails.UserDetailsService {
@Autowired
UserDao userDao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userDao.findByUsername(username);
if (user == null) {
System.out.println("User not found");
throw new UsernameNotFoundException("Username not found");
}
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), true, true, true, true, getGrantedAuthorities(user));
}
private List<GrantedAuthority> getGrantedAuthorities(User user) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
return authorities;
}
}//End of Class