在上一篇文章中,我们学习了 Spring Security 的实现,使用 In-Memory 配置对用户进行身份验证。在此示例中,我们将学习根据数据库表对用户和角色进行身份验证。
如果您是 Spring Security 的新手,我强烈建议您阅读 Spring Security 的基础知识。
执行
为了实现 Spring Security,我们将借助WebSecurityConfigurerAdapter. 要启用 Spring 安全性,我们需要使用@EnableSpringSecurity和注释我们的配置类@Configuration。
在此示例中,我们将使用H2 内存数据库来存储我们的用户凭据并获取这些凭据以进行身份验证。我们将在应用程序启动期间使用@PostConstruct注释将我们的用户凭据添加到数据库中。
复制 复制 COPY COPY@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()。我们重写这个方法来编写我们的逻辑来从数据库中获取数据。
复制 复制 COPY COPY@Componentpublic 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我们将使用的密码编码器。WebSecurityConfigurerAdapterAuthenticationManagerBuilderAuthenticationManagerBuilder`authenticationProvider()DaoAuthenticationProviderUserDetailsServiceImpl
复制 复制 COPY COPY@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
复制 复制 COPY COPY@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。
复制 复制 COPY COPY@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 "Hello, "+ auth.getName()+ " you are "+ role+""; } @GetMapping(value = "/user/message") public String userMessage(Authentication auth) { String role = ""; for (GrantedAuthority gauth: auth.getAuthorities()) { role = gauth.getAuthority(); } return "Hello, "+ auth.getName()+ " you are "+ role+""; } @GetMapping(value = "/any/message") public String anyMessage(Authentication auth) { String role = ""; for (GrantedAuthority gauth: auth.getAuthorities()) { role = gauth.getAuthority(); } return "Hello, "+ auth.getName()+ " you are "+ role+""; }}
现在让我们尝试使用 Postman 来使用这些 API。
输入请求 URL 作为localhost:8080/api/admin/message并在 Authorization 选项卡下,选择 Basic Auth 并提供用户名和密码,然后单击发送。
身份验证成功后,您将能够访问 URL 并将获得输出为 -
如果您尝试通过上述 URL 上的john@mail.com凭据登录,您将收到一条错误消息Forbidden ,因为这仅适用于 ADMIN 角色。
我建议您尝试将其他组合凭据与 URL 资源一起使用,请参阅输出。
概括
在本文中,我们学习了如何实现 Spring Security 并针对数据库对用户进行身份验证,以及如何根据用户角色限制 URL 或资源。
在该系列的后续文章中,我们将继续学习 Spring Security 并查看使用 JWT 和 Spring Security 的身份验证。
最后但并非最不重要的一点是,您总能找到实现的完整源代码 @Github