我们使用jhipster通过OAuth2身份验证生成网关和微服务,并且可以与JHipster Registry和Keycloak服务器一起使用。但我们有一个将从外部服务调用的微服务,该服务使用基本身份验证。
因此,在网关上,我们需要从基本身份验证服务器向keycloak服务器发送登录和密码,并使用访问令牌来调用我们的服务。我通过在MicroserviceSecurityConfiguration类中添加过滤器来获取访问令牌:
http.addFilterBefore(basicAuthFilter, UsernamePasswordAuthenticationFilter.class);
这里有一个过滤方法的摘录:
ResourceOwnerPasswordResourceDetails details = new ResourceOwnerPasswordResourceDetails();
details.setAccessTokenUri("http://keycloakserver/auth/realms/jhipster/protocol/openid-connect/token");
details.setGrantType("password");
details.setClientId("clientId");
details.setClientAuthenticationScheme(AuthenticationScheme.form);
details.setUsername(login);
details.setPassword(password);
AccessTokenRequest tokenRequest = new DefaultAccessTokenRequest();
ResourceOwnerPasswordAccessTokenProvider provider = new ResourceOwnerPasswordAccessTokenProvider();
OAuth2AccessToken accessToken = provider.obtainAccessToken(details, tokenRequest);
我想我必须在tokenStore中存储此令牌,但我不知道如何。所以我的问题是如何使用这个令牌,并且我得到它的方式是否正确?
感谢您的帮助!
答案 0 :(得分:0)
我在生产系统中遇到同样的问题,然后我将认证服务器更改为JHipster UAA服务器,问题解决了。
我认为你现在正在使用第一种:
OAuth 2.0 / OIDC身份验证: 这使用OpenID Connect服务器,如Keycloak或Okta,它处理应用程序之外的身份验证。
使用JHipster UAA服务器进行身份验证: 这使用了必须单独生成的JHipster UAA服务器,它是一个处理应用程序外部身份验证的OAuth2服务器。
答案 1 :(得分:0)
经过一些测试和反复试验,我设法做到了我想要的。
首先,我创建了一个BasicAuthenticationFilter类:
@Configuration
public class BasicAuthenticationFilter implements Filter {
private static final String GRANT_TYPE = "password";
private static final String BASIC_AUTH_HEADER = "Authorization";
private static final String BASIC_PREFIX = "Basic ";
@Value("${security.oauth2.client.access-token-uri}")
private String accessTokenUri;
@Value("${security.oauth2.client.client-id}")
private String clientId;
@Value("${security.oauth2.client.client-secret}")
private String clientSecret;
@Autowired
private TokenStore tokenStore;
private ResourceOwnerPasswordAccessTokenProvider provider;
public BasicAuthenticationFilter( ) {
provider = new ResourceOwnerPasswordAccessTokenProvider();
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
String header = null;
if (request instanceof HttpServletRequest) {
HttpServletRequest httpRequest = (HttpServletRequest) request;
header = httpRequest.getHeader(BASIC_AUTH_HEADER);
if (header != null && header.startsWith(BASIC_PREFIX)) {
String base64 = header.substring(BASIC_PREFIX.length());
String loginPassword = new String(Base64.getDecoder().decode(base64.getBytes()));
String[] split = loginPassword.split(":");
String login = split[0];
String password = split[1];
authenticate(httpRequest, login, password);
}
}
chain.doFilter(request, response);
}
private void authenticate(HttpServletRequest httpRequest, String login, String password) {
ResourceOwnerPasswordResourceDetails details = new ResourceOwnerPasswordResourceDetails();
details.setAccessTokenUri(accessTokenUri);
details.setGrantType(GRANT_TYPE);
details.setClientId(clientId);
details.setClientAuthenticationScheme(AuthenticationScheme.query);
details.setUsername(login);
details.setPassword(password);
DefaultAccessTokenRequest tokenRequest = new DefaultAccessTokenRequest();
tokenRequest.setCurrentUri(httpRequest.getRequestURI());
try {
OAuth2AccessToken accessToken = provider.obtainAccessToken(details, tokenRequest);
OAuth2Authentication oauth2Authentication = tokenStore.readAuthentication(accessToken);
AccessTokenDetails accessTokenDetail = new AccessTokenDetails(accessToken.getValue());
oauth2Authentication.setDetails(accessTokenDetail);
SecurityContext context = SecurityContextHolder.getContext();
context.setAuthentication(oauth2Authentication);
} catch (OAuth2AccessDeniedException e) {
throw new AccessDeniedException("Wrong credentials !");
}
}
@Override
public void destroy() {
}
public static class AccessTokenDetails {
private static final String DEFAULT_TOKEN_TYPE = "bearer";
public final String tokenType;
public final String tokenValue;
public AccessTokenDetails(String tokenValue) {
this(DEFAULT_TOKEN_TYPE, tokenValue);
}
public AccessTokenDetails(String tokenType, String tokenValue) {
this.tokenType = tokenType;
this.tokenValue = tokenValue;
}
}
}
此过滤器检查是否存在基本身份验证,如果是,则验证用户身份。身份验证详细信息存储在内部类AccessTokenDetails中。因此,可以在AuthorizationHeaderUtil中读取令牌:
public class AuthorizationHeaderUtil {
public static String getAuthorizationHeader() {
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
Object details = authentication.getDetails();
String tokenType = "";
String tokenValue = "";
if (details instanceof OAuth2AuthenticationDetails) {
OAuth2AuthenticationDetails oauth2Details = (OAuth2AuthenticationDetails) details;
tokenType = oauth2Details.getTokenType();
tokenValue = oauth2Details.getTokenValue();
} else if (details instanceof AccessTokenDetails) {
AccessTokenDetails accessTokenDetails = (AccessTokenDetails) details;
tokenType = accessTokenDetails.tokenType;
tokenValue = accessTokenDetails.tokenValue;
}
return String.format("%s %s", tokenType, tokenValue);
}
}
这个类是由JHipster生成的,我添加了对我使用的两个身份验证详细信息类的检查。
我希望这会有用。
丹尼斯