4
votes

Comment utiliser RESTful avec l'authentification de base dans Spring Boot

Helllo, j'utilise RESTful avec l'authentification de base et ce code fait partie du RestController:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.crypto.bcrypt.BCryptPasswordEncoder;

import com.dgs.restful.webservices.goaltrackerservice.user.MyUserDetailsService;

@Configuration
@EnableWebSecurity
public class SpringSecurityConfigurationBasicAuth extends WebSecurityConfigurerAdapter {

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Autowired
    private MyUserDetailsService userDetailsService;

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authProvider
          = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(userDetailsService);
        authProvider.setPasswordEncoder(bCryptPasswordEncoder());
        return authProvider;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http
            .csrf().disable()
            .authorizeRequests()
            .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
            .antMatchers("/allusers").permitAll()
                .anyRequest().authenticated()
                .and()
            // .formLogin().and()
            .httpBasic();
        }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider());
    }
}

Et j'ai un problème, par exemple j'utilise Postman pour récupérer le objectifs pour un utilisateur spécifique comme celui-ci:

http: // localhost: 8080 / jpa / users / john / buts avec la requête GET

Ensuite, j'utilise l'authentification de base pour le nom d'utilisateur john et le mot de passe pour ce nom d'utilisateur et je reçois les objectifs pour john.

Après cela, si je fais une requête GET pour ce lien http: // localhost: 8080 / jpa / users / tom / buts Je reçois les buts de tom, mais je suis connecté avec john en ce moment, donc john peut voir ses buts et aussi il peut voir les buts de tom.

La question est de savoir comment accéder au nom d'utilisateur de connexion dans RestController, car je veux faire quelque chose comme ceci:

if (loginUsername == username) {
    return goalJpaRepository.findByUserId(userId);
} 

return "Access denied!";

Donc je veux savoir s'il est possible d'accéder au nom d'utilisateur de connexion à partir de l'en-tête HTTP?

Merci!


MISE À JOUR - Oui, le framework est Spring Boot, aussi J'utilise Spring Security avec l'authentification Dao car je souhaite obtenir l'utilisateur à partir d'une base de données MySQL. De toute façon, je ne suis pas un expert chez Spring Security.

Je comprends maintenant comment utiliser Principal dans mes méthodes de contrôleur, mais je ne sais pas comment utiliser Spring Security pour ce cas spécifique. Comment dois-je le mettre en œuvre? Par exemple, l'utilisateur john ne devrait voir et modifier que ses objectifs.

Configuration de la sécurité Spring:

@GetMapping("/jpa/users/{username}/goals")
public List<Goal> getAllGoals(@PathVariable String username) {
    userId = getUserIdFromUsername(username);
    return goalJpaRepository.findByUserId(userId); 
}

public Long getUserIdFromUsername(String username) {
    User user = userJpaRepository.findByUsername(username);
    userId = user.getId(); 
    return userId;
}


3 commentaires

utilisez-vous le ressort? spécifiquement printemps-sécurité?


Sidenote, quel est le type de données de loginUsername ? Si c'est String , alors vous le comparez mal.


Cela dépend du framework que vous utilisez (si vous en utilisez). Vous parlez de RestController donc je suppose que vous utilisez Spring (vous devez absolument ajouter les balises appropriées à votre question). Si tel est le cas, jetez un œil à la sécurité Spring qui vous permet de configurer comment sécuriser votre application.


4 Réponses :


1
votes

Veuillez noter que vous ne faites aucune sécurité pour le moment.

Comme l'a dit @Matt "Cela dépend du framework que vous utilisez" . Mais je suppose que vous utilisez le ressort. Vous devriez alors jeter un œil à la documentation du module spring-securuty.

En gros, vous pouvez injecter l'utilisateur authentifié dans votre paramètre de méthode:

   @GetMapping("/jpa/users/{username}/goals")
   public List<Goal> getAllGoals(@PathVariable String username, Principal principal) {
     if ( username.equals(principal.getName()) ) {
       userId = getUserIdFromUsername(username);
       return goalJpaRepository.findByUserId(userId); 
     } else {
       throw new SomeExceptionThatWillBeMapped();
     }
   } 

Mais spring -security et de nombreux frameworks fournissent de meilleurs modèles pour gérer la sécurité.


2 commentaires

Merci pour votre réponse! Je viens d'ajouter ceci et cela fonctionne parfaitement. J'utilise déjà Spring Security avec l'authentification Dao, mais je ne sais pas comment utiliser Spring Security pour ce cas spécifique. Je viens de mettre à jour la question si vous voulez jeter un coup d'œil.


Vous auriez dû envisager de créer une nouvelle question pour cela et d'accepter l'une des réponses pour celle-ci.



2
votes

En supposant que vous utilisez Spring comme framework Java, vous devez utiliser la sécurité Spring pour configurer l'authentification de base. Nombreux tutoriels disponibles en ligne ( https://www.baeldung.com/spring-security-basic -authentification ,

Spring Security fournira alors un contexte de sécurité disponible dans toute l'application ( SecurityContextHolder.getContext () ) à partir duquel vous pourrez récupérer les informations de l'utilisateur connecté (nom d'utilisateur, ..) .).

Par exemple, pour récupérer le nom d'utilisateur de l'utilisateur connecté, vous devez faire:

Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String loginUsername = authentication.getName();

Alternativement, comme mentionné par @ gervais.b Spring peut injecter le Principal (ou Authentication ) dans vos méthodes de contrôleur.

Comme dit par @Glains Une alternative encore meilleure est d'utiliser le Annotations @PreAuthorize et @PostAuthorize , qui vous permettent de définir des règles simples basées sur Spring Expression Language.


2 commentaires

Merci Matt pour votre aide, je viens de mettre à jour ma question. J'utilise Spring Boot et j'utilise également Spring Security avec l'authentification Dao car je souhaite extraire l'utilisateur de la base de données. Maintenant, je comprends comment utiliser Principal dans les méthodes du contrôleur pour obtenir ce que je veux, mais je ne sais pas comment utiliser Spring Security pour cela, que dois-je ajouter dans le fichier de configuration de la sécurité Spring?


Spring Security peut vous aider pour les règles générales basées sur les rôles, comme le point de terminaison "/ users / *" est uniquement accessible à l'utilisateur connecté (ou à l'utilisateur avec le rôle X). Et comme @Glains l'a mentionné dans sa réponse, il vous permet également de définir des règles simples avec des annotations telles que @PreAuthorize avec des expressions Spring EL.



1
votes

Vous pouvez également résoudre ce problème avec @PreAuthorize , une annotation proposée par Spring Security Framework, qui utilise le langage d'expression Spring.

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {

}

En coulisses Spring utilisera le SecurityContextHolder déjà mentionné pour récupérer le principal actuellement authentifié. Si l'expression se résout à false, le code de réponse 403 sera renvoyé.

Veuillez noter que vous devez activer la sécurité de la méthode globale:

@PreAuthorize("principal.name == #username")
@GetMapping("/jpa/users/{username}/goals")
public List<Goal> getAllGoals(@PathVariable String username) {
    return goalJpaRepository.findByUserId(userId); 
}


0 commentaires

1
votes

Pour répondre à votre nouvelle question sur "Authentification Dao" , la réponse est de fournir un UserDetailsService personnalisé.

D'après la configuration que vous avez jointe à votre question, il semble que vous disposez déjà d'un MyUserDetailsService .

De nombreux articles expliquent comment utiliser un DetailsService personnalisé. Celui-ci semble correspondre à vos besoins: https: //www.baeldung. com / spring-security-authentication-with-a-database

Modifier : comment être sûr que seul Jean peut voir les éléments de Jean.

Fondamentalement, la seule chose que vous puissiez faire pour vous assurer que seul John peut voir ses objectifs est de restreindre les objectifs uniquement à ceux appartenant à John. Mais il existe de nombreuses façons de le faire.

  1. Comme vous le suggérez dans votre question initiale, vous pouvez simplement sélectionner les objectifs pour un utilisateur spécifique. La puissance de spring-security est qu'elle peut injecter un Principal mais aussi une sorte d'objet d'authentification orher.

  2. Vous pouvez également rendre ce filtre plus implicite du côté DAO / Repository en utilisant le SecurityContextHolder . Cette approche convient et a une meilleure apparence lorsque votre système est plus centré sur l'utilisateur ou ressemble à un système multi-locataire.

  3. Utiliser des @Annotations ou Aspects spécifiques serait également une solution mais peut-être moins évidente dans ce cas.


2 commentaires

Merci mais le problème ne concernait pas "l'authentification Dao", j'ai implémenté ceci ... c'est l'ancien problème, quand j'utilise Postman, je suis connecté avec john et je peux récupérer les objectifs de john et aussi tout les objectifs des autres utilisateurs, je veux autoriser la récupération uniquement des objectifs de john lorsque je suis connecté avec john ... vous avez dit que je pouvais injecter l'utilisateur authentifié dans mon paramètre de méthode, et je l'ai fait et fonctionne parfaitement ... aussi vous avez dit que la sécurité du ressort est meilleure que cela, et je veux savoir comment puis-je utiliser la sécurité du ressort dans cette situation.


J'ai dit que la sécurité printanière est un bon cadre de sécurité. Et, puisque vous êtes au printemps, c'est le choix de fait. Je modifierai cette réponse pour expliquer vos alternatives.