3

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); 
    } 
} 
+0

avez-vous résolu ce problème ?? – KJEjava48

Répondre

0

Nous faisons dans notre projet quelque chose de similaire. Nous envoyons le jeton JWT en tant que partie du corps de la réponse. Le Client écrit en AngularJS prend le jeton et le stocke dans la mémoire du navigateur. Ensuite, pour tous les appels sécurisés ultérieurs, le client intègre le jeton dans l'en-tête de la demande en tant que jeton de support. Notre JSON pour l'authentification ressemble à ceci:

{ 
    "username": "auser", 
    "password": "password", 
    "dbname": "data01" 
} 

et pour chaque demande usiquent nous ajoutons le ci-dessous dans l'en-tête de demande

Bearer <token>