将数据库身份验证添加到Spring Data Rest应用程序

时间:2020-10-19 21:03:43

标签: java spring spring-boot authentication spring-data-rest

我正在使用带有Thymeleaf的Spring Data REST创建应用程序。

最初,我创建了模型,控制器,Dao和服务。一切正常。我现在正尝试为我的应用程序增加安全性。现在,我只是专注于登录/注销。

我已经能够创建一个内存中身份验证,如下所示:

#lang racket

(define lst
  '(("a" "a")
    ("b" "a")
    ("c" "z")
    ("c" "a")
    ("b" "z")
    ("d" "a")
    ("a" "z")
    ("d" "z")))

(define (sort-items-index lst)
  (local [(define index-lst
            (map (λ (s) (string-length (first s))) lst))
          (define (combile-2-str s)
            (string-append (first s) (second s)))
          (define (spilt-str-by-index s n)
            (list (substring s 0 n) (substring s n (string-length s))))]
    (map spilt-str-by-index
         (sort (map combile-2-str lst) string<?)
         index-lst)))

(sort-items-index lst)

(define (sort-items-v2 lst)
  (sort lst (λ (s1 s2)
              (string<?
               (string-append (first s1) (second s1))
               (string-append (first s2) (second s2))))))
        
(sort-items-v2 lst)

我想将其更改为数据库身份验证。我很确定我可以创建一个jdbc连接并将我的config方法更改为如下所示:

@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"));
    }

}

我的问题是我已经通过我的DAO界面访问数据库。例如:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        auth.jdbcAuthentication().dataSource(securityDataSource);
        
}

“我的用户”表的电子邮件和密码列将用作用户名/密码。

是否可以通过某种方式使用此方法进行身份验证?我可以提供其他信息,但不愿意发布所有内容,希望有人会为我编写。

2 个答案:

答案 0 :(得分:1)

假设数据库表名是用户和授权者。 datasource是在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());
                }
    }

答案 1 :(得分: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<>();
            /*
             * 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;
    }
}

并将其连接:

    @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;
    }
}