Spring OAuth2.0:根据客户端ID获取用户角色

我有多个客户注册我的oauth2 auth服务器。 假设user1具有诸如ROLE_AROLE_B用于client1的角色,同一用户具有诸如ROLE_C ,用于ROLE_C ROLE_D 。 现在当用户使用client1client2登录时,他能够看到所有四个角色,即。 ROLE_AROLE_BROLE_CROLE_D

我的要求是当user1登录到client1时,它应该只返回角色ROLE_AROLE_B 。 当他使用ROLE_C登录时,它应该只返回ROLE_CROLE_D

为实现这一目标,我计划的是在身份validationfunction中,我需要获取clientId。 所以使用clientId和用户名我可以从db(client-user-roles-mapping表)中找到分配给用户的相应角色。 但问题是我不知道如何在authenticate函数中获取clientId

  @Override public Authentication authenticate(final Authentication authentication) throws AuthenticationException { String userName = ((String) authentication.getPrincipal()).toLowerCase(); String password = (String) authentication.getCredentials(); if (userName != null && authentication.getCredentials() != null) { String clientId = // HERE HOW TO GET THE CLIENT ID Set userRoles = authRepository.getUserRoleDetails(userName.toLowerCase(), clientId); Collection authorities = fillUserAuthorities(userRoles); Authentication token = new UsernamePasswordAuthenticationToken(userName, StringUtils.EMPTY, authorities); return token; } else { throw new BadCredentialsException("Authentication Failed!!!"); } } else { throw new BadCredentialsException("Username or Password cannot be empty!!!"); } } 

任何人都可以请帮助我

更新1

CustomAuthenticationProvider.java

 @Component public class CustomAuthenticationProvider implements AuthenticationProvider { private final Logger log = LoggerFactory.getLogger(getClass()); @Autowired private LDAPAuthenticationProvider ldapAuthentication; @Autowired private AuthRepository authRepository; public CustomAuthenticationProvider() { super(); } @Override public Authentication authenticate(final Authentication authentication) throws AuthenticationException { String userName = ((String) authentication.getPrincipal()).toLowerCase(); String password = (String) authentication.getCredentials(); if (userName != null && authentication.getCredentials() != null) { String clientId = // HERE HOW TO GET THE CLIENT ID Set userRoles = authRepository.getUserRoleDetails(userName.toLowerCase(), clientId); Collection authorities = fillUserAuthorities(userRoles); Authentication token = new UsernamePasswordAuthenticationToken(userName, StringUtils.EMPTY, authorities); return token; } else { throw new BadCredentialsException("Authentication Failed!!!"); } } else { throw new BadCredentialsException("Username or Password cannot be empty!!!"); } } public boolean invokeAuthentication(String username, String password, Boolean isClientValidation) { try { Map userDetails = ldapAuthentication.authenticateUser(username, password); if(Boolean.parseBoolean(userDetails.get("success").toString())) { return true; } } catch (Exception exception) { log.error("Exception in invokeAuthentication::: " + exception.getMessage()); } return false; } @Override public boolean supports(Class authentication) { return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)); } private Collection fillUserAuthorities(Set roles) { Collection authorties = new ArrayList(); for(String role : roles) { authorties.add(new SimpleGrantedAuthority(role)); } return authorties; } } 

这是修改后的代码

 @Override public Authentication authenticate(final Authentication authentication) throws AuthenticationException { String userName = ((String) authentication.getPrincipal()).toLowerCase(); String password = (String) authentication.getCredentials(); if (userName != null && authentication.getCredentials() != null) { String clientId = getClientId(); // validate client ID before use Set userRoles = authRepository.getUserRoleDetails(userName.toLowerCase(), clientId); Collection authorities = fillUserAuthorities(userRoles); Authentication token = new UsernamePasswordAuthenticationToken(userName, StringUtils.EMPTY, authorities); return token; } else { throw new BadCredentialsException("Authentication Failed!!!"); } } else { throw new BadCredentialsException("Username or Password cannot be empty!!!"); } private String getClientId(){ final HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); final String authorizationHeaderValue = request.getHeader("Authorization"); final String base64AuthorizationHeader = Optional.ofNullable(authorizationHeaderValue) .map(headerValue->headerValue.substring("Basic ".length())).orElse(""); if(StringUtils.isNotEmpty(base64AuthorizationHeader)){ String decodedAuthorizationHeader = new String(Base64.getDecoder().decode(base64AuthorizationHeader), Charset.forName("UTF-8")); return decodedAuthorizationHeader.split(":")[0]; } return ""; } 

有关RequestContextHolder的更多信息

扩展UsernamePasswordAuthenticationToken


POJO不仅需要保存用户名和密码,还需要保存客户端标识符。

 public ExtendedUsernamePasswordAuthenticationToken extends UsernamePasswordAuthenticationToken { private final String clientId; public ExtendedUsernamePasswordAuthenticationToken(Object principal , Object credentials , String clientId) { super(principal, credentials); this.clientId = clientId; } public String getClientId() { return clientId; } } 

扩展UsernamePasswordAuthenticationFilter


需要调整身份validation过程,以便除了用户名和密码之外,还将客户端标识符传递给身份validation代码。

 public class ExtendedUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter { public ExtendedUsernamePasswordAuthenticationFilter () { super(); } @Override public public Authentication attemptAuthentication(HttpServletRequest request , HttpServletResponse response) throws AuthenticationException { // See the source code of UsernamePasswordAuthenticationFilter // to implement this. Instead of creating an instance of // UsernamePasswordAuthenticationToken, create an instance of // ExtendedUsernamePasswordAuthenticationToken, something along // the lines of: final String username = obtainUsername(request); final String password = obtainPassword(request); final String clientId = obtainClientId(request); ... final Authentication authentication = new ExtendedUsernamePasswordAuthenticationToken(username, password, clientId); return getAuthenticationManager().authenticate(authentication); } } 

使用可用于登录的额外信息


 public CustomAuthenticationProvider implements AuthenticationProvider { ... @Override public boolean supports(final Class authentication) { return authentication.isAssignableFrom(ExtendedUsernamePasswordAuthenticationToken.class); } @Override public Authentication authenticate(final Authentication authentication) throws AuthenticationException { } } 

强制Spring Security使用自定义filter


      ...  

或者,如果使用Java配置:

 @Bean public ExtendedUsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter(final AuthenticationManager authenticationManager) { final ExtendedUsernamePasswordAuthenticationFilter filter = new ExtendedUsernamePasswordAuthenticationFilter(); filter.setAuthenticationManager(authenticationManager); return filter; } protected void configure(HttpSecurity http) throws Exception { http.addFilterAt(usernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); ... } 

根据您的要求,因为您只想从请求中访问其他参数,您可以在CustomAuthenticationProvider类中尝试以下内容

 @Autowired private HttpServletRequest request; 

添加以下逻辑以读取httpRequest参数并添加逻辑以访问授权密钥

 @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { Enumeration headerNames = request.getHeaderNames(); while(headerNames.hasMoreElements()) { String headerName = headerNames.nextElement(); System.out.println("Header Name - " + headerName + ", Value - " + request.getHeader(headerName)); } } 

现在,您将拥有编码基本身份validation字段,您可以解码如下所示

 if (authorization != null && authorization.startsWith("Basic")) { // Authorization: Basic base64credentials String base64Credentials = authorization.substring("Basic".length()).trim(); String credentials = new String(Base64.getDecoder().decode(base64Credentials), Charset.forName("UTF-8")); // client/secret = clientId:secret final String[] values = credentials.split(":",2);