多重基本身份验证与Spring安全

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

Multi basic auth with spring security

问题

I want to use basic auth, but I need to use it in UserDetailsService, not only with the username but also with some information from the header (the header contains the type of user).

This is because I have two users with the same names but different types. For example, I have name:user1 type:USER psw: 1 and name:user1 type:PLAYER psw:1. So when I log in as the first user, I should search in the database for a user with name=user1 and type=USER, but UserDetailsService has only the method loadUserByUsername(String login).

So how can I do this?

My UserDetailsService:

  1. public class UserDetailsService implements org.springframework.security.core.userdetails.UserDetailsService {
  2. private final UserService userService;
  3. @Override
  4. @Transactional
  5. public UserDetails loadUserByUsername(String login) throws UsernameNotFoundException {
  6. return userService.findUserDetailsByLogin(login).orElseThrow(() -> new UsernameNotFoundException(login));
  7. }
  8. }
英文:

I want to use basic auth, but i need use in UserDetailsService not only username but also some info from header(header contains type of user). <br>
This is bacause I have 2 users with same names but with varios types. For example, I have name:user1 type:USER psw: 1 and name:user1 type:PLAYER psw:1. So when I login as first user, i should search in db user with name=user1 and type=USER, but UserDetailsService has only this method loadUserByUsername(String login). <br>
So how can i do this?

My UserDetailsService:

  1. public class UserDetailsService implements org.springframework.security.core.userdetails.UserDetailsService {
  2. private final UserService userService;
  3. @Override
  4. @Transactional
  5. public UserDetails loadUserByUsername(String login) throws UsernameNotFoundException {
  6. return userService.findUserDetailsByLogin(login).orElseThrow(() -&gt; new UsernameNotFoundException(login));
  7. }
  8. }

答案1

得分: 1

My solution is to use a static context. Using CustomFilter, I create a context and then use it in the loadUserByUsername method:

  1. @Component
  2. @RequiredArgsConstructor
  3. public class TypeFilter extends OncePerRequestFilter {
  4. private final TypeService typeService;
  5. private final ObjectMapper mapper;
  6. @Override
  7. protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
  8. throws ServletException, IOException {
  9. String uri = request.getRequestURI();
  10. if (!uri.contains("/login") && !uri.contains("/password")) {
  11. chain.doFilter(request, response);
  12. return;
  13. }
  14. String headerValue = request.getHeader(TYPE);
  15. if (StringUtils.isBlank(headerValue)) {
  16. response.setStatus(HttpStatus.BAD_REQUEST.value());
  17. return;
  18. }
  19. try {
  20. Type type = typeService.findByValue(headerValue);
  21. TypeContext.setCurrentType(type);
  22. chain.doFilter(request, response);
  23. } catch (MyException e) {
  24. response.setStatus(HttpStatus.BAD_REQUEST.value());
  25. }
  26. }
  27. }
  28. My config:
  29. @Override
  30. protected void configure(HttpSecurity http) throws Exception {
  31. http
  32. .addFilterBefore(typeFilter, BasicAuthenticationFilter.class);
  33. }
  34. And then I use context in `UserDetailsService`:
  35. ```java
  36. public UserDetails loadUserByUsername(String login) throws UsernameNotFoundException {
  37. Type type = TypeContext.getCurrentType();
  38. return userService.findUser(login, type).orElseThrow(() -> new UsernameNotFoundException(login));
  39. }
英文:

My solution is to use a static context. Using CustomFilter, I create a context and then use it in the loadUserByUsername method

  1. @Component
  2. @RequiredArgsConstructor
  3. public class TypeFilter extends OncePerRequestFilter {
  4. private final TypeService typeService;
  5. private final ObjectMapper mapper;
  6. @Override
  7. protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
  8. throws ServletException, IOException {
  9. String uri = request.getRequestURI();
  10. if (!uri.contains(&quot;/login&quot;) &amp;&amp; !uri.contains(&quot;/password&quot;)) {
  11. chain.doFilter(request, response);
  12. return;
  13. }
  14. String headerValue = request.getHeader(TYPE);
  15. if (StringUtils.isBlank(headerValue)) {
  16. response.setStatus(HttpStatus.BAD_REQUEST.value());
  17. return;
  18. }
  19. try {
  20. Type type = type Service.findByValue(headerValue);
  21. TypeContext.setCurrentType(type);
  22. chain.doFilter(request, response);
  23. } catch (MyException e) {
  24. response.setStatus(HttpStatus.BAD_REQUEST.value());
  25. }
  26. }

}

My config:

  1. @Override
  2. protected void configure(HttpSecurity http) throws Exception {
  3. http
  4. .addFilterBefore(typeFilter, BasicAuthenticationFilter.class)

And then I use context in UserDeatilsService:

  1. public UserDetails loadUserByUsername(String login) throws UsernameNotFoundException {
  2. Type type = TypeContext.getCurrentType();
  3. return userService.findUser(login, type).orElseThrow(() -&gt; new UsernameNotFoundException(login));
  4. }

答案2

得分: -1

你可以将loadUserByUsername(String login)方法包装到另一个方法中。并使用@RequestHeader("YourHeader")提取你想要的附加信息。

英文:

You could warp the loadUserByUsername(String login) method into an other method. And extract with @RequestHeader(&quot;YourHeader&quot;) the additional Information you want.

huangapple
  • 本文由 发表于 2020年7月28日 16:39:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/63130181.html
匿名

发表评论

匿名网友

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

确定