经过一些测试和反复试验,我设法做到了。
首先,我创建了一个 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生成,我为我使用的两个认证细节类添加了一个检查。
希望对你有用。
丹尼斯