【问题标题】:Using Basic auth with OAuth2 and JHipster将基本身份验证与 OAuth2 和 JHipster 一起使用
【发布时间】:2018-01-10 10:31:46
【问题描述】:

我们使用 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 中,但我不知道如何。所以我的问题是如何使用这个令牌,我得到它的方式是否正确?

感谢您的帮助!

【问题讨论】:

    标签: authentication oauth-2.0 jhipster


    【解决方案1】:

    我在生产系统中遇到了同样的问题,然后我将身份验证服务器更改为 JHipster UAA 服务器,问题得到解决。

    我认为你现在使用的是第一种:

    OAuth 2.0 / OIDC 身份验证: 这使用 OpenID Connect 服务器,如 Keycloak 或 Okta,它处理应用程序外部的身份验证。

    使用 JHipster UAA 服务器进行身份验证: 这使用了一个必须单独生成的 JHipster UAA 服务器,它是一个处理应用程序外部身份验证的 OAuth2 服务器。

    【讨论】:

      【解决方案2】:

      经过一些测试和反复试验,我设法做到了。

      首先,我创建了一个 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生成,我为我使用的两个认证细节类添加了一个检查。

      希望对你有用。

      丹尼斯

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-07-29
        • 2021-01-31
        • 2018-11-10
        • 2014-06-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-01
        相关资源
        最近更新 更多