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

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

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:

public class UserDetailsService implements org.springframework.security.core.userdetails.UserDetailsService {
    
    private final UserService userService;

    @Override
    @Transactional
    public UserDetails loadUserByUsername(String login) throws UsernameNotFoundException {
        return userService.findUserDetailsByLogin(login).orElseThrow(() -> new UsernameNotFoundException(login));
    }
}
英文:

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:

public class UserDetailsService implements org.springframework.security.core.userdetails.UserDetailsService {

    private final UserService userService;

    @Override
    @Transactional
    public UserDetails loadUserByUsername(String login) throws UsernameNotFoundException {
        return userService.findUserDetailsByLogin(login).orElseThrow(() -&gt; new UsernameNotFoundException(login));
    }
}

答案1

得分: 1

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

@Component
@RequiredArgsConstructor
public class TypeFilter extends OncePerRequestFilter {
   private final TypeService typeService;
   private final ObjectMapper mapper;

   @Override
   protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
           throws ServletException, IOException {
       String uri = request.getRequestURI();
       if (!uri.contains("/login") && !uri.contains("/password")) {
           chain.doFilter(request, response);
           return;
       }

       String headerValue = request.getHeader(TYPE);

       if (StringUtils.isBlank(headerValue)) {
           response.setStatus(HttpStatus.BAD_REQUEST.value());
           return;
       }

       try {
           Type type = typeService.findByValue(headerValue);
           TypeContext.setCurrentType(type);
           chain.doFilter(request, response);
       } catch (MyException e) {
           response.setStatus(HttpStatus.BAD_REQUEST.value());
       }
   }
}

My config:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .addFilterBefore(typeFilter, BasicAuthenticationFilter.class);
}

And then I use context in `UserDetailsService`:

```java
public UserDetails loadUserByUsername(String login) throws UsernameNotFoundException {
    Type type = TypeContext.getCurrentType();
    return userService.findUser(login, type).orElseThrow(() -> new UsernameNotFoundException(login));
}
英文:

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

@Component
@RequiredArgsConstructor
public class TypeFilter extends OncePerRequestFilter {
private final TypeService typeService;
private final ObjectMapper mapper;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
String uri = request.getRequestURI();
if (!uri.contains(&quot;/login&quot;) &amp;&amp; !uri.contains(&quot;/password&quot;)) {
chain.doFilter(request, response);
return;
}
String headerValue = request.getHeader(TYPE);
if (StringUtils.isBlank(headerValue)) {
response.setStatus(HttpStatus.BAD_REQUEST.value());
return;
}
try {
Type type = type Service.findByValue(headerValue);
TypeContext.setCurrentType(type);
chain.doFilter(request, response);
} catch (MyException e) {
response.setStatus(HttpStatus.BAD_REQUEST.value());
}
}

}

My config:

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

And then I use context in UserDeatilsService:

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

答案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:

确定