Spring OAuth2.0:根据客户端ID获取用户角色
我有多个客户注册我的oauth2 auth服务器。 假设user1具有诸如ROLE_A
, ROLE_B
用于client1的角色,同一用户具有诸如ROLE_C
,用于ROLE_C
ROLE_D
。 现在当用户使用client1或client2登录时,他能够看到所有四个角色,即。 ROLE_A
, ROLE_B
, ROLE_C
和ROLE_D
。
我的要求是当user1登录到client1时,它应该只返回角色ROLE_A
和ROLE_B
。 当他使用ROLE_C
登录时,它应该只返回ROLE_C
和ROLE_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);
- 将自然语言转换为数学方程式
- 安全处理org.xml.sax.SAXNotRecognizedException的解决方案导致在Tomcat中运行java.lang.IllegalStateException
- 线程“main”中的exceptionorg.eclipse.swt.SWTError:swt.mozilla中的XPCOM错误0x80004005
- Maven / Jenkins java.lang.UnsupportedClassVersionError:不支持的major.minor版本51.0
- 系统中发现了selenium元素,但在Jenkins中找不到
- 为什么我们需要有界wilcard
- Hibernate @Transactional Sessions
- .jfindClass中的错误(as.character(driverClass)):找不到类
- 并发log4j