Maison  >  Article  >  Le filtre de sécurité Spring obtient-il des informations de session de Redis ?

Le filtre de sécurité Spring obtient-il des informations de session de Redis ?

PHPz
PHPzavant
2024-02-09 22:30:08471parcourir

L'éditeur PHP Zimo est là pour répondre à la question de savoir si le filtre Spring Security obtient les informations de session de Redis. Spring Security est un cadre de sécurité puissant qui fournit un ensemble complet de mécanismes d'authentification et d'autorisation. Par défaut, Spring Security utilise HttpSession pour gérer les informations de session utilisateur. Cependant, avec la configuration, nous pouvons stocker les informations de session dans un stockage externe tel que Redis. L'avantage est qu'il peut réaliser une gestion de session distribuée et améliorer l'évolutivité du système. Par conséquent, les filtres Spring Security peuvent obtenir des informations de session auprès de Redis.

Contenu de la question

J'essaie d'utiliser spring-boot, spring-security et spring-session pour implémenter le système de connexion et d'utiliser redis comme stockage de la session.

Ma configuration :

@enablewebsecurity
@enablemethodsecurity
@configuration
@requiredargsconstructor
public class securityconfig {


    private final userdetailsservice detailsservice;

    @bean
    public passwordencoder passwordencoder() {
        return new bcryptpasswordencoder();
    }

    @bean
    public authenticationprovider authenticationprovider(passwordencoder passwordencoder) {
        daoauthenticationprovider provider = new daoauthenticationprovider();
        provider.setpasswordencoder(passwordencoder);
        provider.setuserdetailsservice(this.detailsservice);
        return provider;
    }

    @bean
    public authenticationmanager authenticationmanager(authenticationprovider authenticationprovider) {
        return new providermanager(authenticationprovider);
    }

    @bean
    public securityfilterchain filterchain(httpsecurity http) throws exception {
        return http
                .csrf().disable()
                .cors(customizer.withdefaults())
                .authorizehttprequests(auth -> {
                    auth.requestmatchers("/api/v1/auth/register/**", "/api/v1/auth/login").permitall();
                    auth.anyrequest().authenticated();
                })
                .sessionmanagement(sessionmanagement -> sessionmanagement
                        .sessioncreationpolicy(if_required) //
                        .sessionfixation(sessionmanagementconfigurer.sessionfixationconfigurer::newsession) //
                        .maximumsessions(100000) //
                        //.sessionregistry(sessionregistry())
                )
                //.exceptionhandling((ex) -> ex.authenticationentrypoint(this.authentrypoint))
                .logout(out -> out
                        .logouturl("/api/v1/auth/logout")
                        .invalidatehttpsession(true) // invalidate all sessions after logout
                        .deletecookies("jsessionid")
                        .logoutsuccesshandler((request, response, authentication) ->
                                securitycontextholder.clearcontext()
                        )
                )
                .build();
    }

    @bean
    public securitycontextrepository securitycontextrepository() {
        return new httpsessionsecuritycontextrepository();
    }
}

Mon contrôleur de connexion :

@postmapping("/login")
public void login(@requestbody loginform form, httpservletrequest request, httpservletresponse response) {
    string ip = httprequestutil.getip(request);
    string device = httprequestutil.getdevice(request);

    loginformwrapper loginformwrapper = new loginformwrapper(form.email(), form.password(), ip, device);

    authenticationservice.login(loginformwrapper, request, response);
}

et service d'authentification :

@override
public void login(loginformwrapper form, httpservletrequest request, httpservletresponse response) {
    authentication authentication = authenticationmanager.authenticate(usernamepasswordauthenticationtoken.unauthenticated(
            form.email().trim(), form.password()));

    // create a new context
    securitycontext context = securitycontextholder.createemptycontext();
    context.setauthentication(authentication);

    // update securitycontextholder and strategy
    this.securitycontextholderstrategy.setcontext(context);
    this.securitycontextrepository.savecontext(context, request, response);
}

Si j'ai bien compris

this.securitycontextholderstrategy.setcontext(context); L'authentification doit être conservée dans la mémoire de l'application, par exemple dans un contexte threadlocal

.

et

`this.securitycontextrepository.savecontext(context, request, response);`

Les informations de session doivent être enregistrées sur Redis.

Maintenant, lorsque je me connecte, je vois que les données ont été enregistrées sur Redis :

Cependant, en vérifiant ce qui est retourné par ma demande de connexion, je vois :

Identifiant de session complètement différent.

Ma première question est : Pourquoi ces identifiants ne correspondent-ils pas ? Comment Spring sait-il quelle clé rechercher ?

Une autre question est : quel filtre pour obtenir les données de Redis ? J'essaie de déboguer tous les filtres de la chaîne de filtres :

[org.springframework.security.web.session.DisableEncodeUrlFilter@2fedae96,
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@4945cd1f,
org.springframework.security.web.context.SecurityContextHolderFilter@72499396,
org.springframework.security.web.header.HeaderWriterFilter@7048d039,
org.springframework.web.filter.CorsFilter@2dbfcbe4,
org.springframework.security.web.authentication.logout.LogoutFilter@5d5a77de,
org.springframework.security.web.session.ConcurrentSessionFilter@1f8e1096,
org.springframework.security.web.savedrequest.RequestCacheAwareFilter@651bec9a,
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@76d4e1af,
org.springframework.security.web.authentication.AnonymousAuthenticationFilter@6f13ed1,
org.springframework.security.web.session.SessionManagementFilter@642693c2,
org.springframework.security.web.access.ExceptionTranslationFilter@2199e1a4,
org.springframework.security.web.access.intercept.AuthorizationFilter@48c584c]

Mais il semble lire les informations de session à partir de httpserletrequest d'une manière ou d'une autre - cependant, si je supprime la clé de Redis, l'authentification du point de terminaison qui l'exige échoue.

Est-ce que j'ai raté quelque chose ? Dois-je récupérer les informations de session de Redis et les stocker dans httpservlerrequest avant le démarrage de mon fitler ? Ou comment lit-il les données Redis ?

Merci pour votre aide.

Solution

La valeur dans le cookie de session est codée en base64 :

echo '3c048eae-9f73-4df5-a009-bdf802ae37ca' | openssl base64
m2mwndhlywutowy3my00zgy1lwewmdktymrmodayywuzn2nhcg==
echo 'M2MwNDhlYWUtOWY3My00ZGY1LWEwMDktYmRmODAyYWUzN2NhCg==' | openssl base64 -d
3c048eae-9f73-4df5-a009-bdf802ae37ca

Ainsi, lors du décodage en base64, l'identifiant de session du cookie correspond à l'identifiant de session stocké dans Redis.

Si vous ne l'avez pas encore lu, je vous recommande ce document : https://www.php.cn/link/e27c71957d1e6c223e0d48a165da2ee1

Surtout la section « Comprendre les composants de la gestion de session » : https://www.php.cn/link/e27c71957d1e6c223e0d48a165da2ee1#understanding-session-management-components

Vous n'avez pas mentionné la version de Spring Security que vous utilisez, mais je suppose que vous utilisez Spring Security 6. Dans cette section, il y a une phrase liée à l'authentification de session :

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer