我要实现的是使多租户应用程序工作区感知。我的意思是,除了用户名和密码之外,我还在验证工作区。
之前,我具有(有效的)常规身份验证(用户名和密码)和一个JWTFilter,它是一次的PerPerRequestFilter。
我做了什么?
结果总是未经授权的:(
我尝试了什么? 在调试代码时,永远不要传递CustomAuthenticationFilter,这就是我在那儿集中精力的原因。真的不知道我在做什么错。如果您需要更多信息,请大喊。
使用addFilter(authenticationFilter())
替换UsernamePasswordAuthenticationFilter
.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.addFilterAfter(authenticationFilter(), JwtFilter.class);
.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(authenticationFilter(),UsernamePasswordAuthenticationFilter.class);
.addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(jwtAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class);
一些代码。
CustomAuthenticationToken
public class CustomAuthenticationToken extends UsernamePasswordAuthenticationToken {
private String workspace;
public CustomAuthenticationToken(final Object principal,
final Object credentials,
final String workspace) {
super(principal, credentials);
this.workspace = workspace;
}
public CustomAuthenticationToken(final Object principal,
final Object credentials,
final String workspace, Collection<? extends GrantedAuthority> authorities) {
super(principal, credentials, authorities);
this.workspace = workspace;
super.setAuthenticated(true);
}
public String getWorkspace() {
return this.workspace;
}
}
CustomAuthenticationFilter
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private static final String SPRING_SECURITY_FORM_DOMAIN_KEY = "workspace";
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
if (!request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: "
+ request.getMethod());
}
CustomAuthenticationToken authRequest = getAuthRequest(request);
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
private CustomAuthenticationToken getAuthRequest(HttpServletRequest request) {
String username = obtainUsername(request);
String password = obtainPassword(request);
String domain = obtainDomain(request);
if (username == null) {
username = "";
}
if (password == null) {
password = "";
}
if (domain == null) {
domain = "";
}
username = username.trim();
return new CustomAuthenticationToken(username, password, domain);
}
private String obtainDomain(HttpServletRequest request) {
return request.getParameter(SPRING_SECURITY_FORM_DOMAIN_KEY);
}
}
CustomUserDetailsAuthenticationProvider
@Component
public class CustomUserDetailsAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
/**
* The plaintext password used to perform
* PasswordEncoder#matches(CharSequence, String)} on when the user is
* not found to avoid SEC-2056.
*/
private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword";
private final PasswordEncoder customPasswordEncoder;
private final CustomUserDetailsService customUserDetailsService;
private String userNotFoundEncodedPassword;
public CustomUserDetailsAuthenticationProvider(final PasswordEncoder customPasswordEncoder,
final CustomUserDetailsService customUserDetailsService) {
this.customPasswordEncoder = customPasswordEncoder;
this.customUserDetailsService = customUserDetailsService;
}
@Override
protected void additionalAuthenticationChecks(final UserDetails userDetails,
final UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
if (authentication.getCredentials() == null) {
logger.debug("Authentication failed: no credentials provided");
throw new BadCredentialsException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
}
final String presentedPassword = authentication.getCredentials().toString();
if (!customPasswordEncoder.matches(presentedPassword, userDetails.getPassword())) {
logger.debug("Authentication failed: password does not match stored value");
throw new BadCredentialsException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
}
}
@Override
protected UserDetails retrieveUser(final String username,
final UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
final CustomAuthenticationToken auth = (CustomAuthenticationToken) authentication;
UserDetails loadedUser;
try {
loadedUser = this.customUserDetailsService.loadUserByWorkspaceAndUsername(auth.getWorkspace(), auth.getPrincipal().toString());
} catch (UsernameNotFoundException notFound) {
if (authentication.getCredentials() != null) {
String presentedPassword = authentication.getCredentials().toString();
customPasswordEncoder.matches(presentedPassword, userNotFoundEncodedPassword);
}
throw notFound;
} catch (Exception repositoryProblem) {
throw new InternalAuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);
}
if (loadedUser == null) {
throw new InternalAuthenticationServiceException("UserDetailsService returned null, which is an interface contract violation");
}
return loadedUser;
}
@Override
protected void doAfterPropertiesSet() throws Exception {
Assert.notNull(this.customUserDetailsService, "A UserDetailsService must be set");
this.userNotFoundEncodedPassword = this.customPasswordEncoder.encode(USER_NOT_FOUND_PASSWORD);
}
}
CustomUserDetailsServiceImpl
@Component
public class CustomUserDetailsServiceImpl implements CustomUserDetailsService {
private static final Logger LOGGER = LoggerFactory.getLogger(com.cliwise.security.workspace.CustomUserDetailsServiceImpl.class);
private final LoginAttemptService loginAttemptService;
private final UserRepository userRepository;
private final HttpServletRequest request;
public CustomUserDetailsServiceImpl(LoginAttemptService loginAttemptService, UserRepository userRepository, HttpServletRequest request) {
this.loginAttemptService = loginAttemptService;
this.userRepository = userRepository;
this.request = request;
}
@Override
public UserDetails loadUserByWorkspaceAndUsername(String workspace, String username) throws UsernameNotFoundException {
final User user = userRepository.findByUsernameOrEmailAndWorkspace(username, username, workspace)
.orElseThrow(() -> new UserNotFoundException("User not found with username or email : " + username));
return UserPrincipal.create(user);
}
}
最后但并非最不重要的 WebSecurity
@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
private final CustomAuthenticationEntryPoint unauthorizedHandler;
private final CustomUserDetailsAuthenticationProvider customUserDetailsAuthenticationProvider;
public WebSecurity(final CustomAuthenticationEntryPoint unauthorizedHandler,
final CustomUserDetailsAuthenticationProvider customUserDetailsAuthenticationProvider) {
this.unauthorizedHandler = unauthorizedHandler;
this.customUserDetailsAuthenticationProvider = customUserDetailsAuthenticationProvider;
}
@Override
public void configure(final AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.authenticationProvider(customUserDetailsAuthenticationProvider);
}
@Bean
public CustomAuthenticationFilter authenticationFilter() throws Exception {
CustomAuthenticationFilter filter = new CustomAuthenticationFilter();
filter.setAuthenticationManager(authenticationManagerBean());
return filter;
}
@Bean(BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.httpBasic().disable()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler)
.and()
.exceptionHandling().accessDeniedHandler(accessDeniedHandler())
.and()
.addFilterBefore(jwtAuthenticationFilter(), CustomAuthenticationFilter.class);
http
.authorizeRequests()
.antMatchers("/auth").permitAll()
.anyRequest()
.authenticated();
}
@Bean
public AccessDeniedHandler accessDeniedHandler() {
return new CustomAccessDeniedHandler();
}
@Bean
public JwtFilter jwtAuthenticationFilter() {
return new JwtFilter();
}
}
提前感谢您的时间。
答案 0 :(得分:0)
我的理解是,您在CustomUserDetailsAuthenticationProvider中面临问题。由于您正在扩展AbstractUserDetailsAuthenticationProver,因此您将获得
的默认实现。public Authentication authenticate(Authentication authentication)
throws AuthenticationException;
查看其是否正确验证了身份验证对象,否则,您将不得不重写该方法并编写自己的实现。