我有一个Spring Boot 2.0应用程序,可作为我的角度应用程序的后端(提供休息服务)。
我们正在使用LDAP身份验证进行登录。它工作得很好。我们已经使用spring-oauth-2和spring-ldap实现了自定义代码。
现在,我们已经集成了执行器。我希望执行器端点可以通过基本身份验证在浏览器中访问。
为此,我使用@Order(1)添加了WebSecurityConfigurerAdapter的实现。它在浏览器中运行良好。但是,当我从angualar应用程序调用登录URL时,它给我/ oauth / token URL的401未经授权的错误,因此我无法从ui应用程序登录。
我们将帮助您解决此错误。
班级:
@Configuration
@Order(1)
public class FormLoginWebSecurityConfigurerAdapter extends
WebSecurityConfigurerAdapter {
@Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("actuator")
.password(passwordEncoder().encode("actuator")).roles("ACTUATOR_ADMIN");
}
@Override
protected void configure(final HttpSecurity http) throws Exception {
http.antMatcher("/actuator/**").authorizeRequests().anyRequest().hasRole("ACTUATOR_ADMIN").and()
.httpBasic();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
谢谢。
答案 0 :(得分:0)
所以我自己遇到了这个问题(OAuth + Basic Auth),最终选择了一条不同的路径,该路径对于Basic Auth而言涉及更多,但最终还是有效。
首先,您需要实现自己的Authentication
对象:
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import java.util.Collection;
import java.util.Collections;
public class ActuatorAuthentication implements Authentication {
private static final Object DUMMY = new Object();
private static final String NAME = "Actuator Authenticated";
private static final boolean AUTHENTICATED = true;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Collections.emptyList();
}
@Override
public Object getCredentials() {
return DUMMY;
}
@Override
public Object getDetails() {
return DUMMY;
}
@Override
public Object getPrincipal() {
return DUMMY;
}
@Override
public boolean isAuthenticated() {
return authenticated;
}
@Override
public void setAuthenticated(boolean b) throws IllegalArgumentException {
throw new UnsupportedOperationException("Operation setAuthenticated not supported.");
}
@Override
public String getName() {
return NAME;
}
}
我们将使用它与AutoConfiguredHealthEndpointGroup.isAuthorized()
方法配合使用,以在配置以下内容后切换所需的行为:
management:
endpoint:
health:
show-details: when_authorized
因此,我们将使用它来实现自己的OncePerRequestFilter
,它将对除/health
,/health/liveness
和/health/readiness
以外的所有执行器端点执行实际的基本身份验证。
如果未提供基本身份验证,我们还将确保仅/health
会返回基本UP
或DOWN
。
此代码最终为:
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class ActuatorSecurityFilter extends OncePerRequestFilter {
private static final String[] EXCLUDED_ENDPOINTS = {
"/actuator/health/liveness",
"/actuator/health/readiness",
"/actuator/info"
};
private AntPathMatcher pathMatcher = new AntPathMatcher();
private final String username;
private final String password;
public ActuatorSecurityFilter(String username, String password) {
this.username = username;
this.password = password;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
boolean authorized = false;
String authorization = request.getHeader("Authorization");
if (authorization != null) {
// Authorization: Basic base64credentials
String base64Credentials = authorization.substring("Basic".length()).trim();
byte[] credDecoded = Base64.getDecoder().decode(base64Credentials);
String credentials = new String(credDecoded, StandardCharsets.UTF_8);
// credentials = username:password
final String[] values = credentials.split(":", 2);
if (values.length == 2 && username.equals(values[0]) && password.equals(values[1])) {
authorized = true;
}
}
// Handle specific non-auth vs. auth for actuator health
if (pathMatcher.match("/actuator/health", request.getRequestURI())) {
if (authorized) {
// Utilize Dummy Authentication to show full details
Authentication authentication = new ActuatorAuthentication();
SecurityContextHolder.getContext().setAuthentication(authentication);
} else {
// Ensure no authentication is provided to show basic details if auth is incorrect
SecurityContextHolder.getContext().setAuthentication(null);
}
} else if (!authorized) {
response.sendError(401);
return;
}
chain.doFilter(request, response);
}
@Override
protected boolean shouldNotFilter(HttpServletRequest request) {
for (String endpoint : EXCLUDED_ENDPOINTS) {
if (pathMatcher.match(endpoint, request.getRequestURI())) {
return true;
}
}
return false;
}
}
最后,我们希望将其与我们自己的Configuration类连接在一起
import com.cantire.sps.application.filter.ActuatorSecurityFilter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ActuatorSecurityConfiguration {
@Value("${actuator.username}")
private String username;
@Value("${actuator.password}")
private String password;
@Bean
FilterRegistrationBean<ActuatorSecurityFilter> securityFilterRegistration() {
FilterRegistrationBean<ActuatorSecurityFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new ActuatorSecurityFilter(username, password));
registration.addUrlPatterns("/actuator/*");
return registration;
}
}
然后我们只需要将其添加到您的应用程序属性中即可:
actuator:
username: monitor
password: password
Voila,无论您实施了什么WebSecurityConfigurerAdapter,您都可以在Actuator端点上使用基本身份验证。