Je construis une API RESTful basée sur Spring, Jersey, Spring Security et Tomcat. J'ai trouvé ce tutoriel qui semble génial mais qui ne raconte jamais comment authentifier les utilisateurs, ce qui semble être une pièce majeure (Stateless Authentication with Spring Security and JWT)Authentification de jeton de sécurité de printemps Comment authentifier?
Quoi qu'il en soit, j'ai basé mon implémentation à partir de ça et maintenant j'ai du mal à comprendre comment authentifier et récupère le jeton.
J'ai fourni ce que je pensais être tout le code relatif ci-dessous. Maintenant, la question est de savoir comment m'authentifier et récupérer un jeton. Je l'ai essayé avec ça mais je ne récupère pas Token dans les en-têtes de réponse.
@Component
@Path("/auth")
@Produces(MediaType.APPLICATION_JSON)
public class AuthenticationEndPoint {
private UserSecurityService userService;
@Inject
public AuthenticationEndPoint(UserSecurityService userService) {
this.userService = userService;
}
@POST
public void doSomething(CredentialsDTO credentials) {
SecurityUser user = userService.loadUserByUsername(credentials.getUserName());
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getUsername(),credentials.getPassword(),user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(token);
}
}
Voici ma configuration Spring Security
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@Order(2)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Inject
private StatelessAuthenticationFilter statelessAuthenticationFilter;
@Inject
private UserSecurityService userSecurityService;
@Inject
public SecurityConfig() {
super(true);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.exceptionHandling().and()
.anonymous().and()
.servletApi().and()
.headers().cacheControl().and()
.authorizeRequests()
// allow anonymous resource requests
.antMatchers("/").permitAll()
.antMatchers("/favicon.ico").permitAll()
.antMatchers("/public/**").permitAll()
// allow login
.antMatchers("/api/auth").permitAll()
// all other requests require authentication
.anyRequest().authenticated().and()
// token based authentication
.addFilterBefore(statelessAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userSecurityService).passwordEncoder(bCryptPasswordEncoder());
}
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManagerBean();
}
}
utilisateur personnalisée:
public class SecurityUser extends User {
private org.company.app.domain.User user;
public SecurityUser(org.company.app.domain.User user,
Collection<GrantedAuthority> grantedAuthorities) {
super(user.getEmail(),user.getPasswordEncoded(),grantedAuthorities);
this.user = user;
}
public org.company.app.domain.User getUser() {
return user;
}
public void setUser(org.company.app.domain.User user) {
this.user = user;
}
public Collection<Role> getRoles() {
return this.user.getRoles();
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("user", user)
.toString();
}
}
Filtre:
@Service
public class StatelessAuthenticationFilter extends GenericFilterBean {
private final TokenAuthenticationService tokenAuthenticationService;
@Inject
public StatelessAuthenticationFilter(TokenAuthenticationService tokenAuthenticationService) {
this.tokenAuthenticationService = tokenAuthenticationService;
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
Authentication authentication = tokenAuthenticationService.getAuthentication((HttpServletRequest) servletRequest);
SecurityContextHolder.getContext().setAuthentication(authentication);
filterChain.doFilter(servletRequest, servletResponse);
SecurityContextHolder.getContext().setAuthentication(null);
}
}
TokenAuthenticationService
@Service
public class TokenAuthenticationService {
private static final String AUTH_HEADER_NAME = "X-AUTH-TOKEN";
private final TokenHandler tokenHandler;
@Inject
public TokenAuthenticationService(TokenHandler tokenHandler) {
this.tokenHandler = tokenHandler;
}
public String addAuthentication(HttpServletResponse response, UserAuthentication authentication) {
final SecurityUser user = (SecurityUser) authentication.getDetails();
String token = tokenHandler.createTokenForUser(user);
response.addHeader(AUTH_HEADER_NAME, token);
return token;
}
public Authentication getAuthentication(HttpServletRequest request) {
final String token = request.getHeader(AUTH_HEADER_NAME);
if (token != null) {
final SecurityUser user = tokenHandler.parseUserFromToken(token);
if (user != null) {
return new UserAuthentication(user);
}
}
return null;
}
}
TokenHandler:
@Service
public class TokenHandler {
private Environment environment;
private final UserSecurityService userService;
private final String secret;
@Inject
public TokenHandler(Environment environment, UserSecurityService userService) {
this.environment = environment;
this.secret = this.environment.getRequiredProperty("application.security.secret");
this.userService = userService;
}
public SecurityUser parseUserFromToken(String token) {
String username = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody()
.getSubject();
return userService.loadUserByUsername(username);
}
public String createTokenForUser(SecurityUser user) {
return Jwts.builder()
.setSubject(user.getUsername())
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
}
La mise en œuvre de l'interface d'authentification Spring Security
public class UserAuthentication implements Authentication {
private final SecurityUser user;
private boolean authenticated = true;
public UserAuthentication(SecurityUser user) {
this.user = user;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return user.getAuthorities();
}
@Override
public Object getCredentials() {
return user.getPassword();
}
@Override
public Object getDetails() {
return user;
}
@Override
public Object getPrincipal() {
return user.getUsername();
}
@Override
public boolean isAuthenticated() {
return authenticated;
}
@Override
public void setAuthenticated(boolean b) throws IllegalArgumentException {
this.authenticated = b;
}
@Override
public String getName() {
return user.getUsername();
}
}
Enfin mon implémentation de l'interface UserDetailsService
@Service
public class UserSecurityService implements UserDetailsService {
private static final Logger logger = LoggerFactory.getLogger(UserSecurityService.class);
private UserService userService;
@Inject
public UserSecurityService(UserService userService) {
this.userService = userService;
}
private final AccountStatusUserDetailsChecker detailsChecker = new AccountStatusUserDetailsChecker();
@Override
public SecurityUser loadUserByUsername(String s) throws UsernameNotFoundException {
logger.debug("Attempting authentication with identifier {}", s);
User user = userService.getUserByUserName(s);
if (user == null) {
throw new UsernameNotFoundException(String.format("User with identifier %s was not found",s));
}
Collection<GrantedAuthority> authorities = new HashSet<>();
for (Role role : user.getRoles()) {
authorities.add(new SimpleGrantedAuthority(role.getSpringName()));
}
return new SecurityUser(user,authorities);
}
}
avez-vous résolu ce problème ?? – KJEjava48