在上一篇文章中,我们学习了 Spring Security 的实现,使用 In-Memory 配置对用户进行身份验证。在此示例中,我们将学习根据数据库表对用户和角色进行身份验证。
如果您是 Spring Security 的新手,我强烈建议您阅读 Spring Security 的基础知识。
执行
为了实现 Spring Security,我们将借助WebSecurityConfigurerAdapter
. 要启用 Spring 安全性,我们需要使用@EnableSpringSecurity
和注释我们的配置类@Configuration
。
在此示例中,我们将使用H2 内存数据库来存储我们的用户凭据并获取这些凭据以进行身份验证。我们将在应用程序启动期间使用@PostConstruct
注释将我们的用户凭据添加到数据库中。
@PostConstruct
public void setup() {
userRepositoty.save(new UserEntity(1, "shail@mail.com", passwordEncoder.encode("shail@123"), "ROLE_ADMIN"));
userRepositoty.save(new UserEntity(2, "john@mail.com", passwordEncoder.encode("john@123"), "ROLE_USER"));
}
为了根据数据库表对我们的用户进行身份验证,我们将使用DaoAuthenticationProvider
类和UserDetailsService
接口。
DaoAuthenticationProvider
是其中一种实现,AuthenticationProvider
它借助UserDetailsService
检索用户名和密码来对用户进行身份验证。-
UserDetailsService
接口有一个只读方法loadUserByUsername()
。我们重写这个方法来编写我们的逻辑来从数据库中获取数据。复制复制COPYCOPY@Component public class UserDetailsServiceImpl implements UserDetailsService { @Autowired private UserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { UserEntity user = userRepository .findByUsername(username) .orElseThrow(() -> new UsernameNotFoundException("INVALID USERNAME")); UserDetails userDetails = new User(username, user.getPassword(), AuthorityUtils.createAuthorityList(user.getRole())); return userDetails; } }
我们需要重写作为参数的configure()
方法。有一个将 AuthenticationProvider 作为参数的方法;我们将把我们的对象作为参数传递给这个方法。我们还需要告诉我们的 ``DaoAuthenticationProvider我们将使用的密码编码器。WebSecurityConfigurerAdapter
AuthenticationManagerBuilder
AuthenticationManagerBuilder
`authenticationProvider()
DaoAuthenticationProviderUserDetailsServiceImpl
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
DaoAuthenticationProvider daoAuthProvider = new DaoAuthenticationProvider();
daoAuthProvider.setPasswordEncoder(passwordEncoder());
daoAuthProvider.setUserDetailsService(userDetailsServiceImpl);
auth.authenticationProvider(daoAuthProvider);
}
我们还需要覆盖另一个作为参数的configure()
方法。在这里,我们将为不同的 URI 模式和这些 URI 模式上允许的角色配置我们的基本安全参数。WebSecurityConfigurerAdapterHttpSecurity
@Override
public void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.httpBasic().and()
.authorizeRequests()
.antMatchers("/h2-console/**").permitAll()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.antMatchers("/api/user/**").hasRole("USER")
.antMatchers("/api/any/**").hasAnyRole("ADMIN", "USER")
.anyRequest()
.authenticated()
.and().formLogin().disable();
http.csrf().ignoringAntMatchers("/h2-console/**");
http.headers().frameOptions().sameOrigin();
// @formatter:on
}
测试
为了测试我们的实现,让我们创建一个简单的控制器,其中包含一些返回不同消息的 GetMapping。
@RestController
@RequestMapping(value = "api")
public class MessageController {
@GetMapping(value = "/admin/message")
public String adminMessage(Authentication auth) {
String role = "";
for (GrantedAuthority gauth: auth.getAuthorities()) {
role = gauth.getAuthority();
}
return "<h1>Hello, "+ auth.getName()+ " you are "+ role+"</h1>";
}
@GetMapping(value = "/user/message")
public String userMessage(Authentication auth) {
String role = "";
for (GrantedAuthority gauth: auth.getAuthorities()) {
role = gauth.getAuthority();
}
return "<h1>Hello, "+ auth.getName()+ " you are "+ role+"</h1>";
}
@GetMapping(value = "/any/message")
public String anyMessage(Authentication auth) {
String role = "";
for (GrantedAuthority gauth: auth.getAuthorities()) {
role = gauth.getAuthority();
}
return "<h1>Hello, "+ auth.getName()+ " you are "+ role+"</h1>";
}
}
现在让我们尝试使用 Postman 来使用这些 API。
输入请求 URL 作为localhost:8080/api/admin/message并在 Authorization 选项卡下,选择 Basic Auth 并提供用户名和密码,然后单击发送。
身份验证成功后,您将能够访问 URL 并将获得输出为 -
如果您尝试通过上述 URL 上的john@mail.com凭据登录,您将收到一条错误消息Forbidden ,因为这仅适用于 ADMIN 角色。
![](https://i-blog.csdnimg.cn/blog_migrate/ce73fda19c8509362c6cd457dff856eb.png)
我建议您尝试将其他组合凭据与 URL 资源一起使用,请参阅输出。
概括
在本文中,我们学习了如何实现 Spring Security 并针对数据库对用户进行身份验证,以及如何根据用户角色限制 URL 或资源。
在该系列的后续文章中,我们将继续学习 Spring Security 并查看使用 JWT 和 Spring Security 的身份验证。
最后但并非最不重要的一点是,您总能找到实现的完整源代码 @Github