使用带有OAuth2和JHipster的Basic auth

时间:2018-01-10 10:31:47

标签: authentication oauth-2.0 jhipster

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

感谢您的帮助!

2 个答案:

答案 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生成的,我添加了对我使用的两个身份验证详细信息类的检查。

我希望这会有用。

丹尼斯