我使用inMemoryAuthentication,并且需要在访问特定端点时以编程方式验证用户(出于测试原因)。因此,我使用基于Programmatically login in a user using spring security的以下方法:
private void login(Role role) {
logger.warn("Login User with role: " + role.toString());
Authentication auth =
new UsernamePasswordAuthenticationToken("user", "password", getAuthorities(role));
SecurityContext securityContext = SecurityContextHolder.getContext();
securityContext.setAuthentication(auth);
}
private Collection<GrantedAuthority> getAuthorities(Role role) {
Collection<GrantedAuthority> grantedAuthorities = new ArrayList<>();
GrantedAuthority grantedAuthority = (GrantedAuthority) () -> role.toString();
grantedAuthorities.add(grantedAuthority);
return grantedAuthorities;
}
正确设置了securityContext(getAuthentication按预期返回用户),但是未设置JSESSIONID cookie。
答案 0 :(得分:0)
我可以解决我的问题,但这并不容易,我不确定是否有更好的解决方案。
我创建了一个过滤器,一个自定义authenticationProvider和一个自定义authenticationToken
public class E2EAuthenticationFilter extends GenericFilterBean {
private final Logger logger = LoggerFactory.getLogger(E2EAuthenticationFilter.class);
private AuthenticationManager authenticationManager;
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
Role role = null;
String username = null;
String password = null;
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
if(isLoginRequest(request.getRequestURI())){
String roleName = getRoleName(request.getRequestURI());
switch(roleName.toUpperCase()){
case "ADMIN":
role = Role.ADMIN;
username = "admin";
password = "admin";
break;
case "REPORTER":
role = Role.REPORTER;
username = "reporter";
password = "reporter";
break;
default:
break;
}
authenticateUser(username, password, role);
}
chain.doFilter(request, response);
}
public AuthenticationManager getAuthenticationManager() {
return authenticationManager;
}
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
private Collection<GrantedAuthority> getAuthorities(Role role) {
Collection<GrantedAuthority> grantedAuthorities = new ArrayList<>();
GrantedAuthority grantedAuthority = (GrantedAuthority) () -> "ROLE_"+role.toString();
grantedAuthorities.add(grantedAuthority);
return grantedAuthorities;
}
private String getRoleName(String uri){
String[] requestUriParts = uri.split("/");
return requestUriParts[requestUriParts.length-1];
}
private void authenticateUser(String username, String password, Role role){
E2EAuthenticationToken token = new E2EAuthenticationToken(username, password, getAuthorities(role));
Authentication authResult = authenticationManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(authResult);
}
private boolean isLoginRequest(String uri) {
return uri.matches("\\/e2e\\/auth\\/login\\/(\\w)+");
}
}
authProvider类:
@Component
public class E2EAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
E2EAuthenticationToken token = (E2EAuthenticationToken) authentication;
E2EAuthenticationToken authenticated = new E2EAuthenticationToken(token.getUsername(), token.getPassword(), token.getAuthorities());
authenticated.setAuthenticated(true);
return authenticated;
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(E2EAuthenticationToken.class);
}
}
令牌类:
public class E2EAuthenticationToken extends AbstractAuthenticationToken {
private String username;
private String password;
public E2EAuthenticationToken(String username, String password, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.username = username;
}
@Override
public Object getCredentials() {
return this.username;
}
@Override
public Object getPrincipal() {
return this.username;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
最后弹簧配置:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class InMemorySecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private E2EAuthenticationProvider e2eAuthenticationProvider;
@Bean
public E2EAuthenticationFilter e2eAuthenticationFilter() throws Exception {
E2EAuthenticationFilter filter = new E2EAuthenticationFilter();
filter.setAuthenticationManager( authenticationManager() );
return filter;
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(e2eAuthenticationProvider);
auth.inMemoryAuthentication()
.withUser("admin")
.password("admin")
.roles(Role.ADMIN.name())
.and()
.withUser("reporter")
.password("reporter")
.roles(Role.REPORTER.name());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers("/api/**", "/e2e/auth/**", "/acuator/**")
.and().addFilterBefore(e2eAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/actuator/health").permitAll()
.antMatchers("/actuator/info").permitAll()
.anyRequest().authenticated()
.and().httpBasic()
.and().csrf().disable();
}
}
您可能已经注意到,我将此代码用于端点(当然仅在E2E配置中可用)以登录用户进行硒测试。