为Spring Data Rest应用程序添加数据库认证。

huangapple go评论68阅读模式
英文:

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(&quot;securityDataSource&quot;)
	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(&quot;paul&quot;).password(&quot;test123&quot;).roles(&quot;MEMBER&quot;, &quot;ADMIN&quot;))
		.withUser(users.username(&quot;sandra&quot;).password(&quot;test123&quot;).roles(&quot;MEMBER&quot;, &quot;ADMIN&quot;))
		.withUser(users.username(&quot;matthew&quot;).password(&quot;test123&quot;).roles(&quot;MEMBER&quot;));
	}

}

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&lt;User, Integer&gt; {
	
	// method to sort by last name
	public List&lt;User&gt; 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(&quot;select username,password,enabled from users WHERE username=?&quot;)
                .authoritiesByUsernameQuery(&quot;select username,authority from authorities where username=?&quot;)
                .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&lt;User&gt; optional = userRepository.findBy...(username);
            HashSet&lt;GrantedAuthority&gt; set = new HashSet&lt;&gt;();
            /*
             * 根据需要将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&lt;Credential&gt; credential = credentialRepository.findById(username);
            Optional&lt;Authority&gt; authority = authorityRepository.findById(username);
            HashSet&lt;GrantedAuthority&gt; set = new HashSet&lt;&gt;();

            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&lt;User&gt; optional = userRepository.findBy...(username);
            HashSet&lt;GrantedAuthority&gt; set = new HashSet&lt;&gt;();
            /*
             * 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&lt;Credential&gt; credential = credentialRepository.findById(username);
            Optional&lt;Authority&gt; authority = authorityRepository.findById(username);
            HashSet&lt;GrantedAuthority&gt; set = new HashSet&lt;&gt;();

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

huangapple
  • 本文由 发表于 2020年10月20日 05:03:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/64435069.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定