Spring OAuth2.0:根据客户端ID

时间:2018-03-12 06:51:57

标签: java spring spring-security oauth-2.0 spring-security-oauth2

我为oauth2 auth服务器注册了多个客户端。假设 user1 对{strong> client1 具有ROLE_AROLE_B等角色,同一用户拥有ROLE_C等{},{{1}等角色} client2 。现在,当用户使用 client1 client2 登录时,他可以看到所有四个角色,即。 ROLE_DROLE_AROLE_BROLE_C

我的要求是当 user1 登录 client1 时,它应仅返回角色ROLE_DROLE_A。当他使用 client2 登录时,它应仅返回ROLE_BROLE_C

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

ROLE_D

任何人都可以帮助我

更新1

CustomAuthenticationProvider.java

 @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<String> userRoles = authRepository.getUserRoleDetails(userName.toLowerCase(), clientId);
                Collection<SimpleGrantedAuthority> 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!!!");
         }         
    }

3 个答案:

答案 0 :(得分:2)

以下是修改后的代码

@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<String> userRoles = authRepository.getUserRoleDetails(userName.toLowerCase(), clientId);
            Collection<SimpleGrantedAuthority> 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

的更多信息

答案 1 :(得分:1)

扩展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

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

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使用自定义过滤器

<bean class="com.path.to.filter.ExtendedUsernamePasswordAuthenticationFilter" id="formAuthenticationFilter">
  <property name="authenticationManager" ref="authenticationManager"/>
</bean>

<http ... >
  <security:custom-filter position="FORM_LOGIN_FILTER" ref="formAuthenticationFilter"/>

  ...
</http>

或者,如果使用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);
      ...
}

答案 2 :(得分:1)

根据您的要求,由于您只想从请求中访问其他参数,因此您可以在 $ldate=""; while($row = $result->fetch_assoc()){ $lamt=$row['Loan_Amount']; $today=time(); if(empty(strtotime($row['loan_date1']))){ $timespan=(time()-strtotime($row['Loan_Date']))/(60*60*24); $month=round($timespan/31); $ldate=$row['Loan_Date'];} if(strtotime($row['loan_date1'])>0 and empty(strtotime($row['loan_date2']))){ $timespan=(time()-strtotime($row['loan_date1']))/(60*60*24); $month=round($timespan/31); $ldate=$row['loan_date1']; } Print '<td align="center" style="width:100px;">'.date("d M Y",strtotime($ldate)). "</td>"; 课程中试用以下内容

CustomAuthenticationProvider

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

@Autowired
    private HttpServletRequest request;

现在,您将拥有编码基本身份验证字段,您可以像下面那样解码

@Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

    Enumeration<String> headerNames = request.getHeaderNames();
    while(headerNames.hasMoreElements()) {
        String headerName = headerNames.nextElement();
        System.out.println("Header Name - " + headerName + ", Value - " + request.getHeader(headerName));
   }
}