我正在尝试使用Spring boot SSO + Zuul创建一个简单的API网关。我需要将OAuth范围转换为标头,其他后端服务将进一步使用这些标头来基于标头执行RBAC。
我正在使用这个CustomOAuth2TokenRelayFilter,它将在发送到后端之前基本上设置标头。我的问题是如何从当前令牌中获取作用域。OAuth2AuthenticationDetails类确实提供令牌值,但不提供范围。
我不确定如何在其中获取范围。
以下是自定义Zuul过滤器,该过滤器主要来自https://github.com/spring-cloud/spring-cloud-security/blob/master/spring-cloud-security/src/main/java/org/springframework/cloud /security/oauth2/proxy/OAuth2TokenRelayFilter.java
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.client.OAuth2RestOperations;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
import org.springframework.stereotype.Component;
@Component
public class CustomOAuth2TokenRelayFilter extends ZuulFilter {
private static Logger LOGGER = LoggerFactory.getLogger(CustomOAuth2TokenRelayFilter.class);
private static final String ACCESS_TOKEN = "ACCESS_TOKEN";
private static final String TOKEN_TYPE = "TOKEN_TYPE";
private OAuth2RestOperations restTemplate;
public void setRestTemplate(OAuth2RestOperations restTemplate) {
this.restTemplate = restTemplate;
}
@Override
public int filterOrder() {
return 1;
}
@Override
public String filterType() {
return "pre";
}
@Override
public boolean shouldFilter() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth instanceof OAuth2Authentication) {
Object details = auth.getDetails();
if (details instanceof OAuth2AuthenticationDetails) {
OAuth2AuthenticationDetails oauth = (OAuth2AuthenticationDetails) details;
RequestContext ctx = RequestContext.getCurrentContext();
LOGGER.debug ("role " + auth.getAuthorities());
LOGGER.debug("scope", ctx.get("scope")); // How do I obtain the scope ??
ctx.set(ACCESS_TOKEN, oauth.getTokenValue());
ctx.set(TOKEN_TYPE, oauth.getTokenType()==null ? "Bearer" : oauth.getTokenType());
return true;
}
}
return false;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
ctx.addZuulRequestHeader("x-pp-user", ctx.get(TOKEN_TYPE) + " " + getAccessToken(ctx));
return null;
}
private String getAccessToken(RequestContext ctx) {
String value = (String) ctx.get(ACCESS_TOKEN);
if (restTemplate != null) {
// In case it needs to be refreshed
OAuth2Authentication auth = (OAuth2Authentication) SecurityContextHolder
.getContext().getAuthentication();
if (restTemplate.getResource().getClientId()
.equals(auth.getOAuth2Request().getClientId())) {
try {
value = restTemplate.getAccessToken().getValue();
}
catch (Exception e) {
// Quite possibly a UserRedirectRequiredException, but the caller
// probably doesn't know how to handle it, otherwise they wouldn't be
// using this filter, so we rethrow as an authentication exception
throw new BadCredentialsException("Cannot obtain valid access token");
}
}
}
return value;
}
}
您可以将OAuth2ClientContext注入到过滤器中,并用于oAuth2ClientContext.getAccessToken().getScope()
检索范围。
OAuth2ClientContext是一个会话范围的Bean,其中包含当前访问令牌和保留状态。
因此,如果我们将其应用于您的示例,它将看起来像这样:
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestOperations;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
import org.springframework.stereotype.Component;
@Component
public class CustomOAuth2TokenRelayFilter extends ZuulFilter {
private static Logger LOGGER = LoggerFactory.getLogger(CustomOAuth2TokenRelayFilter.class);
private static final String ACCESS_TOKEN = "ACCESS_TOKEN";
private static final String TOKEN_TYPE = "TOKEN_TYPE";
private OAuth2RestOperations restTemplate;
@Autowired
private OAuth2ClientContext oAuth2ClientContext;
public void setRestTemplate(OAuth2RestOperations restTemplate) {
this.restTemplate = restTemplate;
}
@Override
public int filterOrder() {
return 1;
}
@Override
public String filterType() {
return "pre";
}
@Override
public boolean shouldFilter() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth instanceof OAuth2Authentication) {
Object details = auth.getDetails();
if (details instanceof OAuth2AuthenticationDetails) {
OAuth2AuthenticationDetails oauth = (OAuth2AuthenticationDetails) details;
RequestContext ctx = RequestContext.getCurrentContext();
LOGGER.debug ("role " + auth.getAuthorities());
LOGGER.debug("scope" + oAuth2ClientContext.getAccessToken().getScope());
ctx.set(ACCESS_TOKEN, oauth.getTokenValue());
ctx.set(TOKEN_TYPE, oauth.getTokenType()==null ? "Bearer" : oauth.getTokenType());
return true;
}
}
return false;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
ctx.addZuulRequestHeader("x-pp-user", ctx.get(TOKEN_TYPE) + " " + getAccessToken(ctx));
return null;
}
private String getAccessToken(RequestContext ctx) {
String value = (String) ctx.get(ACCESS_TOKEN);
if (restTemplate != null) {
// In case it needs to be refreshed
OAuth2Authentication auth = (OAuth2Authentication) SecurityContextHolder
.getContext().getAuthentication();
if (restTemplate.getResource().getClientId()
.equals(auth.getOAuth2Request().getClientId())) {
try {
value = restTemplate.getAccessToken().getValue();
}
catch (Exception e) {
// Quite possibly a UserRedirectRequiredException, but the caller
// probably doesn't know how to handle it, otherwise they wouldn't be
// using this filter, so we rethrow as an authentication exception
throw new BadCredentialsException("Cannot obtain valid access token");
}
}
}
return value;
}
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句