从零蛋开始集成Spring Security 5 (三)

742 阅读2分钟

「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战」。

承接上文...

3.4 实现UserDetailsService

实现UserDetails, 创建了自己的用户类后, 还需要实现UserDetailsService, 将用户信息从数据库中查询出来

UserDetails相同, 先来看一下官方文档:

3-4-1 UserDtails官方文档.png

只有一个根据用户名查询用户的方法, 实现起来并不困难

笔者使用的是MyBatis, 先创建查询仓库接口UserRepository:

public interface UserRepository {
​
  /**
   * 根据用户名查询用户信息
   *
   * @param username 用户名
   * @return 用户实体
   */
  User loadUserByUsername(@Param("username") String username);
​
}

具体的查询语句需要根据实际使用的数据库编写

需要注意的是, user结果中的角色属性roles应包含其对应的权限属性permissions, permissions中又应包含接口属性apis

创建用户服务类UserService:

@Component
@Data
@AllArgsConstructor
public class UserService implements UserDetailsService {
​
  private final UserRepository repository;
​
  @Override
  public UserDetail loadUserByUsername(String username) throws UsernameNotFoundException {
    return repository.loadUserByUsername(username);
  }
​
}

3.5 Spring Security 5 配置

只剩下最后一步, 把刚才手动实现的内容进行配置, 告诉Spring Security就好啦

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
​
  private final UserDetailRepository userDetailRepository;
​
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable()
      .authorizeRequests().anyRequest().authenticated()
      .and()
      .formLogin();
  }
​
  @Override
  @Bean
  @ConditionalOnMissingBean
  public UserDetailsService userDetailsServiceBean() {
    return new UserDetailsServiceImpl(userDetailRepository);
  }
​
}

authenticated开启接口权限校验, formLogin开启默认表单登录

这里有个小坑, 我们需要手动配置一下PasswordEncoder:

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
​
  // 其它配置...
​
  @Bean
  public PasswordEncoder passwordEncoder() {
    return PasswordEncoderFactories.createDelegatingPasswordEncoder();
  }
​
}

至此为止, 所有的Spring Security集成已经完成, 增加个测试用例ExampleApi:

@RestController
@RequestMapping(value = "/api/v1/example")
public interface ExampleApi {
​
  /**
   * 分页查询
   *
   * @param parameters 查询条件
   * @param pageable   分页
   * @return 分页结果
   */
  @GetMapping(value = "")
  @PreAuthorize("hasAuthority('api:example:search')")
  RestDataResult<Page<Example>> search(SearchParameter parameters, Pageable pageable);
    
}

利用@PreAuthorize注解声明接口权限校验规则, 例如上述代码中, 访问/api/v1/example需要用户拥有api:example:search权限

4 问题

本文所完成的登录认证存在如下两个问题:

  1. 使用Spring Security默认登录页面, 丑
  2. 有状态登录, 关闭浏览器或重启应用后, 登录状态将失效, 需要重新登录

笔者将会在下篇文章中继续集成Spring Security, 引入Jwt, 实现无状态模式登录

5 拓展阅读