英文:
Add database authentication to Spring Data Rest application
问题
我正在使用Spring Data REST与Thymeleaf创建一个应用程序。
最初我创建了我的模型、控制器、数据访问对象和服务。一切都运行得很好。我现在想要在我的应用程序中添加安全性。现在我只关注登录/注销功能。
我已经能够创建一个内存中的身份验证,如下所示:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("securityDataSource")
private DataSource securityDataSource;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 为内存中的身份验证添加用户
UserBuilder users = User.withDefaultPasswordEncoder();
auth.inMemoryAuthentication()
.withUser(users.username("paul").password("test123").roles("MEMBER", "ADMIN"))
.withUser(users.username("sandra").password("test123").roles("MEMBER", "ADMIN"))
.withUser(users.username("matthew").password("test123").roles("MEMBER"));
}
}
然而,我想要将这个更改为数据库身份验证。我相信我可以创建一个JDBC连接,并将我的配置方法更改为类似这样的内容:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(securityDataSource);
}
但我的问题是,我已经通过我的数据访问对象接口访问数据库。例如:
public interface UserRepository extends JpaRepository<User, Integer> {
// 按姓氏排序的方法
public List<User> findAllByOrderByLastNameAsc();
}
我的用户表有一个电子邮件和密码列,这将用作用户名/密码。
是否有可能以某种方式也通过这种方式进行身份验证?我可以提供其他信息,但不愿意只是发布所有内容,希望有人会为我编写代码。
英文:
I'm creating an application using Spring Data REST with Thymeleaf.
Initially I created my models, controllers, dao and services. All worked fine. I'm now trying to add security to my application. Right now I'm just focused on the login/logout.
I've been able to create an in memory authentication as below:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("securityDataSource")
private DataSource securityDataSource;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// add users for in memory authentication
UserBuilder users = User.withDefaultPasswordEncoder();
auth.inMemoryAuthentication()
.withUser(users.username("paul").password("test123").roles("MEMBER", "ADMIN"))
.withUser(users.username("sandra").password("test123").roles("MEMBER", "ADMIN"))
.withUser(users.username("matthew").password("test123").roles("MEMBER"));
}
}
I want to change this to database authentication though. I'm pretty sure I can create a jdbc connection and change my config method to something like this:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(securityDataSource);
}
My problem is that I'm already accessing the database through my DAO interfaces. E.g:
public interface UserRepository extends JpaRepository<User, Integer> {
// method to sort by last name
public List<User> findAllByOrderByLastNameAsc();
}
My users table has an email and password column which will be used as the username/password.
Is it possible to also authenticate by using this in some way? I can provide additional information but am reluctant to just post everything and hope somebody will write it for me.
答案1
得分: 1
假设数据库表名为users和authorities。数据源配置在application.yml文件中。
@Autowired
private DataSource dataSource;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery("select username,password,enabled from users WHERE username=?")
.authoritiesByUsernameQuery("select username,authority from authorities where username=?")
.passwordEncoder(new BCryptPasswordEncoder());
}
}
英文:
suppose db table name is users and authorities. dataSource is configured in application.yml.
@Autowired
private DataSource dataSource;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery("select username,password,enabled from users WHERE username=?")
.authoritiesByUsernameQuery("select username,authority from authorities where username=?")
.passwordEncoder(new BCryptPasswordEncoder());
}
}
答案2
得分: 1
由于您已经创建了DAO接口,创建UserDetailsService
实现可能会更容易:
@Service
@NoArgsConstructor @ToString @Log4j2
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired private UserRepository userRepository = null;
@Override
@Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
org.springframework.security.core.userdetails.User user = null;
try {
Optional<User> optional = userRepository.findBy...(username);
HashSet<GrantedAuthority> set = new HashSet<>();
/*
* 根据需要将SimpleGrantedAuthority添加到set中
*/
user = new org.springframework.security.core.userdetails.User(username, optional.get().getPassword(), set);
} catch (UsernameNotFoundException exception) {
throw exception;
} catch (Exception exception) {
throw new UsernameNotFoundException(username);
}
return user;
}
}
然后通过以下方式进行连接:
@Autowired private UserDetailsService userDetailsService = null;
... private PasswordEncoder passwordEncoder = ...;
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder);
}
为了更清晰,这是我的实现的完整上下文:
@Service
@NoArgsConstructor @ToString @Log4j2
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired private CredentialRepository credentialRepository = null;
@Autowired private AuthorityRepository authorityRepository = null;
@Override
@Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = null;
try {
Optional<Credential> credential = credentialRepository.findById(username);
Optional<Authority> authority = authorityRepository.findById(username);
HashSet<GrantedAuthority> set = new HashSet<>();
if (authority.isPresent()) {
authority.get().getGrants().stream()
.map(Authorities::name)
.map(SimpleGrantedAuthority::new)
.forEach(set::add);
}
user = new User(username, credential.get().getPassword(), set);
} catch (UsernameNotFoundException exception) {
throw exception;
} catch (Exception exception) {
throw new UsernameNotFoundException(username);
}
return user;
}
}
英文:
Since you've already created the DAO interfaces, it may be easier to create
a UserDetailsService
implementation:
@Service
@NoArgsConstructor @ToString @Log4j2
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired private UserRepository userRepository = null;
@Override
@Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
org.springframework.security.core.userdetails.User user = null;
try {
Optional<User> optional = userRepository.findBy...(username);
HashSet<GrantedAuthority> set = new HashSet<>();
/*
* Add SimpleGrantedAuthority to set as appropriate
*/
user = new org.springframework.security.core.userdetails.User(username, optional.get().getPassword(), set);
} catch (UsernameNotFoundException exception) {
throw exception;
} catch (Exception exception) {
throw new UsernameNotFoundException(username);
}
return user;
}
}
and wire it in with:
@Autowired private UserDetailsService userDetailsService = null;
... private PasswordEncoder passwordEncoder = ...;
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder);
}
For some additional clarity, here is the complete context of my implementation:
@Service
@NoArgsConstructor @ToString @Log4j2
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired private CredentialRepository credentialRepository = null;
@Autowired private AuthorityRepository authorityRepository = null;
@Override
@Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = null;
try {
Optional<Credential> credential = credentialRepository.findById(username);
Optional<Authority> authority = authorityRepository.findById(username);
HashSet<GrantedAuthority> set = new HashSet<>();
if (authority.isPresent()) {
authority.get().getGrants().stream()
.map(Authorities::name)
.map(SimpleGrantedAuthority::new)
.forEach(set::add);
}
user = new User(username, credential.get().getPassword(), set);
} catch (UsernameNotFoundException exception) {
throw exception;
} catch (Exception exception) {
throw new UsernameNotFoundException(username);
}
return user;
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论