如何在spring security中为来自两个不同表的不同用户配置身份验证?
Posted
技术标签:
【中文标题】如何在spring security中为来自两个不同表的不同用户配置身份验证?【英文标题】:How to configure authentication in spring security for different users from two different tables? 【发布时间】:2020-07-08 15:57:24 【问题描述】:在我的 Spring Boot 应用程序中,我有 2 种不同类型的用户 - 用户和供应商,它们存储在我的 SQL DB 的不同表中。
我只允许访问返回 JWT 的 /user/login 和 /vendor/login。
我无法理解如何配置 spring security 在有人请求 /user/login 时仅检查 USERS 表,而在供应商请求 /vendor/login 时仅检查 VENDORS 表。这可能吗?如果没有,任何人都可以建议我如何配置 Spring Security 以对来自不同表的用户进行身份验证?
这是我当前的配置,仅对用户进行身份验证 -
@Configuration
@EnableWebSecurity
public class SecurityConfigurer extends WebSecurityConfigurerAdapter
@Autowired
private UserService myUserDetailsService; // this fetches data from the USERS table
@Autowired
private JwtRequestFilter jwtRequestFilter;
// *** How do I configure this to check both VENDORS OR USERS table? ***
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
auth.userDetailsService(myUserDetailsService).passwordEncoder(passwordEncoder());
@Override
protected void configure(HttpSecurity http) throws Exception
http.csrf().disable().authorizeRequests()
.antMatchers("/user/auth/login").permitAll()
.antMatchers("/vendor/auth/login").permitAll()
.anyRequest().authenticated()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception
return super.authenticationManagerBean();
@Bean
public BCryptPasswordEncoder passwordEncoder()
return new BCryptPasswordEncoder();
我为用户和供应商实现了 UserDetailsService。这是 userService 的实现 -
@Service
public class UserService implements UserDetailsService
@Autowired
private UserRepository repository;
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
public UserService()
public UserService(UserRepository repository)
this.repository = repository;
public Users findOne(String id)
Optional<Users> user = repository.findById(id);
return user.orElse(null);
public List<Users> findAll()
List<Users> users = new ArrayList<>();
repository.findAll().forEach(users::add);
return users;
public Users insert(Users user) throws UnknownError
// somecode here
public Users update(String id, Users user)
// some code here
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
final Users user = findByEmail(username);
if (user == null)
throw new UsernameNotFoundException("No user Found");
return new User(user.getEmail(), user.getPassword(), new ArrayList<>());
这里是UserController(VendorController和这个类似)-
@RestController
@RequestMapping(path = "/user")
public class AuthController
@Autowired
UserService service;
@Autowired
AuthenticationManager authenticationManager;
@PostMapping(path = "/login")
public ResponseEntity<?> login(@RequestBody AuthenticationRequest form) throws Exception
try
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(form.getEmail(), form.getPassword()));
catch (Exception e)
throw new Exception("Incorrect Credentials");
final UserDetails user = service.loadUserByUsername(form.getEmail());
Users returnedUser = service.insert(user);
ResponseStructure response = new ResponseStructure(true, returnedUser);
return ResponseEntity.ok(response);
【问题讨论】:
【参考方案1】:您可以让 UserService 查找两个存储库
@Service
public class UserService implements UserDetailsService
@Autowired
private UserRepository userRepository;
@Autowired
private VendorRepository vendorRepository;
// all the other stuff
private Users findByUsername(String username)
return userRepository.findByUserName(username);
private Vendors findByVendorName(String vendorName)
return VendorRepository.findByVendorName(vendorName); // given you have such method declared in the Spring Data repository
@Override
public UserDetails loadUserByName(String name) throws UsernameNotFoundException
Users user = findByUsername(name);
if (user != null)
return new User(user.getEmail(), user.getPassword(), new ArrayList<>());
Vendors vendor = findByVendorName(name);
if (vendor != null)
return new Vendor(vendor.getEmail(), vendor.getPassword(), new ArrayList<>());
else
throw new UsernameNotFoundException("No user Found");
【讨论】:
谢谢,但这不是一个理想的解决方案,因为我们首先要遍历 users 表,然后是 vendor 表,其次,如果供应商或用户有相同的名称和密码,那可能惹麻烦。 注意到您的请求来自不同的登录网址。也许你可以添加一个 userType 到 AuthenticationRequest 并根据用户类型选择正确的存储库。 您可以将 userType 属性添加为登录表单上的隐藏输入以使其简单 或者您可以将 HttpServletRequest 作为参数添加到登录方法并使用 getRequestURI() 来了解请求的位置来自以上是关于如何在spring security中为来自两个不同表的不同用户配置身份验证?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Spring Security 中为 x 框架选项提供请求匹配器?
如何在jsp中为spring security auth异常显示自定义错误消息
Spring:HttpSession在集群Tomcat故障转移中为SPRING_SECURITY_CONTEXT返回了空对象
如何在 Spring Security 中为所有请求添加 jwt 身份验证标头?