Я отлаживал в течение 10 часов и, похоже, не могу понять, почему я постоянно получаю неверные учетные данные в Spring Security.
Я действительно вижу, что я беру пользователя из базы данных в моем userdetailsservice
. Пароли совпадают правильно (не хэшируя / не кодируя что-либо в настоящее время), но, когда я углубляюсь в структуру, я получаю исключение несоответствия кредитов.
Честно говоря, у меня нет идей, я чувствую, что сейчас переписываю этот код 3-4 раза, но безрезультатно.
Я нажимаю /login
, чтобы сгенерировать токен.
Jwt Security Config
import com.schachte.asciiphile.security.messaging.JwtAuthenticationEntryPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@Configuration
@Order(1)
public class JwtSecurityConfig extends WebSecurityConfigurerAdapter {
private static final String ROOT_CTX_MATCH_PATH = "/phile/**";
@Autowired
private JwtAuthenticationEntryPoint entryPoint;
@Qualifier("userDetailsServiceImpl")
@Autowired
private UserDetailsService userDetailsService;
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.anyRequest().authenticated()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(new JwtLoginFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class);
http.headers().cacheControl();
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
}
Фильтр входа Jwt
import com.fasterxml.jackson.databind.ObjectMapper;
import com.schachte.asciiphile.model.JwtAuthententicationToken;
import com.schachte.asciiphile.model.User;
import com.schachte.asciiphile.security.util.JwtGenerator;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.auth0.jwt.JWT;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import static com.auth0.jwt.algorithms.Algorithm.HMAC512;
import java.io.IOException;
import java.util.Date;
import java.util.List;
public class JwtLoginFilter extends UsernamePasswordAuthenticationFilter {
private JwtGenerator jwtGenerator = new JwtGenerator();
private AuthenticationManager authenticationManager;
public JwtLoginFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@Override
public Authentication attemptAuthentication(
HttpServletRequest req, HttpServletResponse res)
throws AuthenticationException {
User creds = null;
try {
creds = new ObjectMapper()
.readValue(req.getInputStream(), User.class);
} catch (IOException e) {
e.printStackTrace();
}
List<GrantedAuthority> grantedAuthorities = AuthorityUtils
.commaSeparatedStringToAuthorityList(creds.getRole());
return authenticationManager.authenticate(
new JwtAuthententicationToken(
creds.getUsername(),
creds.getPassword(),
grantedAuthorities
)
);
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication auth) throws IOException, ServletException {
super.successfulAuthentication(request, response, chain, auth);
String token = JWT.create()
.withSubject(((User) auth.getPrincipal()).getUsername())
.withExpiresAt(new Date(System.currentTimeMillis() + 864_000_000))
.sign(HMAC512("secret".getBytes()));
response.addHeader("Authorization", "Token " + token);
}
}
токен аутентификации Jwt
import lombok.Data;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import java.util.List;
@Data
public class JwtAuthententicationToken extends UsernamePasswordAuthenticationToken {
private String username;
private String password;
private List<GrantedAuthority> grantedAuthorities;
public JwtAuthententicationToken(String username, String password, List<GrantedAuthority> grantedAuthorities) {
super(null, null);
this.username = username;
this.password = password;
this.grantedAuthorities = grantedAuthorities;
}
@Override
public Object getCredentials() {
return null;
}
@Override
public Object getPrincipal() {
return this.username;
}
}
Пользовательские данные пользователя
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
public class CustomUserDetails extends User implements UserDetails {
private Collection<? extends GrantedAuthority> authorities;
public CustomUserDetails(final User user, Collection<? extends GrantedAuthority> authorities) {
super(user);
this.authorities = authorities;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getUsername() {
return super.getUsername();
}
@Override
public String getPassword() {
return super.getPassword();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
Пользователь
import javax.persistence.*;
import lombok.Data;
@Entity
@Data
public class User {
public User() {}
public User(String username, String pass, String role) {
this.username = username;
this.password = pass;
this.role = role;
}
public User(User username) {
this.email = username.getEmail();
this.password = username.getPassword();
this.premium = username.getPremium();
this.storedBytes = username.getStoredBytes();
this.username = username.getUsername();
}
@Id
@Column(name = "username")
private String username;
@Column(name = "password")
private String password;
@Column(name = "email")
private String email;
@Column(name = "premium")
private int premium;
@Column(name = "storedbytes")
private int storedBytes;
@Column(name = "role")
private String role;
}
Сведения о пользователе Сервис
import com.schachte.asciiphile.model.CustomUserDetails;
import com.schachte.asciiphile.model.User;
import com.schachte.asciiphile.repository.UserRepo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.Optional;
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserRepo applicationUserRepository;
public UserDetailsServiceImpl(UserRepo applicationUserRepository) {
this.applicationUserRepository = applicationUserRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Optional<User> applicationUser = applicationUserRepository.findByUsername(username);
if (!applicationUser.isPresent()) {
throw new UsernameNotFoundException(username);
}
return new CustomUserDetails(applicationUser.get(), AuthorityUtils
.commaSeparatedStringToAuthorityList(applicationUser.get().getRole()));
}
}