[JAVA] Mémo d'utilisation de Spring Security Remember-Me

Histoire de base et systématique Histoire de certification / autorisation Histoire CSRF Histoire de gestion de session L'histoire de l'en-tête de la réponse Histoire de la sécurité de la méthode Histoire CORS L'histoire de Run-As Histoire ACL Test story Parlez de la coopération avec MVC et Boot

Édition supplémentaire Ce que Spring Security peut et ne peut pas faire

Qu'est-ce que la certification Remember-Me?

J'écris souvent «Rester connecté» ou «Rester connecté pendant ○ semaines» sur l'écran de connexion des services Web.

Hello World

la mise en oeuvre

namespace

applicationContext.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:sec="http://www.springframework.org/schema/security"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
         http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
         http://www.springframework.org/schema/security
         http://www.springframework.org/schema/security/spring-security.xsd">

    <sec:http>
        <sec:intercept-url pattern="/login" access="permitAll" />
        <sec:intercept-url pattern="/**" access="isAuthenticated()" />
        <sec:form-login />
        <sec:logout />
        <sec:remember-me />★ Souviens-toi maintenant-Moi est activé
    </sec:http>
    
    <sec:authentication-manager>
        <sec:authentication-provider>
            <sec:user-service>
                <sec:user
                    name="hoge"
                    password="hoge"
                    authorities="" />
            </sec:user-service>
        </sec:authentication-provider>
    </sec:authentication-manager>
</beans>

Java Configuration

python


package sample.spring.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
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 java.util.Collections;

@EnableWebSecurity
@ComponentScan
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/login").permitAll()
                .anyRequest().access("isAuthenticated()")
                .and()
                .formLogin()
                .and()
                .rememberMe(); //★ Souviens-toi ici-Autorise moi
    }
    
    @Autowired
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("hoge")
            .password("hoge")
            .authorities(Collections.emptyList());
    }
}

Contrôle de fonctionnement

Lorsque vous ouvrez l'écran de connexion (/ login), une case à cocher intitulée Se souvenir de moi sur cet ordinateur. est ajoutée (Écran de connexion par défaut. 032ed0fa27a239bdc1cc #% E3% 83% AD% E3% 82% B0% E3% 82% A4% E3% 83% B3% E3% 83% 9A% E3% 83% BC% E3% 82% B8% E3% 82% 92 % E6% 8C% 87% E5% AE% 9A% E3% 81% 99% E3% 82% 8B) uniquement lors de l'utilisation). Dans un premier temps, essayez de vous connecter sans le vérifier.

spring-security.jpg

Après vous être connecté, vérifiez le cookie de votre navigateur.

spring-security.jpg

Le JSESSIONID est enregistré. Supprimez-le, puis redessinez l'écran.

spring-security.jpg

Naturellement, vous serez renvoyé à l'écran de connexion.

Ensuite, connectez-vous avec la case à cocher «Se souvenir de moi sur cet ordinateur». Sur l'écran de connexion coché.

spring-security.jpg

Si vous regardez le cookie après vous être connecté, vous verrez que JSESSIONID et un autre, Remember-me, sont stockés.

spring-security.jpg

Supprimez à nouveau JSESSIONID et redessinez l'écran.

spring-security.jpg

Ensuite, l'écran peut être redessiné sans passer à l'écran de connexion. En regardant le cookie, JSESSIONID est stocké avec une valeur différente de celle d'avant.

Comment ça fonctionne

--Remember-Me est activé lors de la connexion lorsqu'un paramètre nommé Remember-me est ajouté aux paramètres de connexion

spring-security.jpg

À propos de KEY

La KEY utilisée pour signer pointe vers n'importe quelle chaîne qui peut être spécifiée dans l'attribut «key» de «» dans le fichier de configuration.

applicationContext.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:sec="http://www.springframework.org/schema/security"
       ...>
    
    ...
    
    <sec:http>
        ...
        <sec:remember-me key="foobar" />
    </sec:http>
    
    ...
</beans>

Cependant, cet attribut est facultatif, sinon une chaîne aléatoire générée à l'aide de SecureRandom sera utilisée.

Je pense qu'il est plus sûr d'utiliser SecureRandom, mais cette valeur n'est générée qu'une seule fois lorsque l'application démarre. Donc, si vous redémarrez l'application en utilisant SecureRandom, tous les cookies Remember-me enregistrés par le client seront invalidés. (Étant donné que la valeur de la signature change lorsque la clé change, une erreur se produit toujours lors de la vérification de la signature.)

Il semble que vous deviez spécifier une chaîne de caractères fixe si vous souhaitez conserver le cookie «Remember-me» que possède le client même si vous redémarrez l'application.

Précautions lors de l'utilisation de la fonction Remember-Me par défaut

―― En raison du mécanisme ci-dessus, si vous connaissez la valeur de Cookie, vous pouvez facilement usurper.

Que devez-vous faire si vous l'utilisez sérieusement

Activer l'attribut sécurisé du cookie

Si vous activez l'attribut sécurisé du cookie, le cookie ne sera envoyé que pour la communication https. Si vous envoyez un cookie via une communication http non cryptée, il peut être intercepté par un tiers et le cookie peut être volé, ce paramètre doit donc être activé.

Si vous utilisez Spring Securty, vous pouvez activer l'attribut sécurisé du cookie utilisé par Remember-Me en définissant:

namespace

applicationContext.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:sec="http://www.springframework.org/schema/security"
       ...>
    
    ...
    
    <sec:http>
        ...
        <sec:remember-me use-secure-cookie="true" />
    </sec:http>
    
    ...
</beans>

Définissez true sur l'attribut ʻuse-secure-cookie de la balise `.

Java Configuration

python


package sample.spring.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
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 java.util.Collections;

@EnableWebSecurity
@ComponentScan
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/login").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .and()
                .rememberMe()
                .useSecureCookie(true);
    }
    
    ...
}

ʻUseSecureCookie (true) `est défini.

Ne pas autoriser l'exécution de traitements importants lors de la connexion avec Remember-Me

Ne faites pas entièrement confiance à la connexion Remember-Me et exigez à nouveau une authentification par mot de passe avant tout processus vraiment important. Le traitement important comprend, par exemple, la mise à jour des données ou l'accès à une page affichant des informations personnelles.

Ce faisant, même si le cookie Remember-Me est volé et usurpé, vous pouvez l'empêcher d'effectuer des actions vraiment importantes.

Je pense que c'est celui qui demande souvent un mot de passe avant de valider une commande sur un site d'achat en ligne (probablement).

Pour Spring Security, Expressions de contrôle d'accès (http://qiita.com/opengl-8080/items/032ed0fa27a239bdc1cc#%E5%BC%8F%E3%83%99%E3%83%BC%E3% 82% B9% E3% 81% A7% E3% 81% AE% E3% 82% A2% E3% 82% AF% E3% 82% BB% E3% 82% B9% E5% 88% B6% E5% BE% Dans A1), vous pouvez utiliser une expression qui considère que ce n'est pas Remember-Me, comme ʻisFullyAuthenticated () `, donc vous pouvez l'utiliser.

namespace

applicationContext.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:sec="http://www.springframework.org/schema/security"
       ...>
    
    ...
    
    <sec:http>
        <sec:intercept-url pattern="/login" access="permitAll" />
        <sec:intercept-url pattern="/remember-me/high-level" access="isFullyAuthenticated()" />
        <sec:intercept-url pattern="/**" access="isAuthenticated()" />
        ...
        <sec:remember-me />
    </sec:http>
    
    ...
</beans>

Java Configuration

MySpringSecurityConfig.java


package sample.spring.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
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 java.util.Collections;

@EnableWebSecurity
@ComponentScan
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/login").permitAll()
                .antMatchers("/remember-me/high-level").fullyAuthenticated()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .and()
                .rememberMe();
    }
    
    ...
}

Il est défini de telle sorte que si vous accédez à / Remember-me / high-level, vous devez être entièrement authentifié (FullyAuthenticated ()).

De plus, nous avons préparé un simple servlet qui renvoie simplement le chemin à ce moment lors de l'accès à / Remember-me / *.

** Contrôle de fonctionnement **

spring-security.jpg

Connectez-vous avec Remember-Me activé.

spring-security.jpg

Supprimez JSESSIONID du cookie (faites-le comme une session morte)

Si vous accédez à nouveau à la page d'accueil dans cet état, la connexion automatique par Remember-Me sera exécutée et la page d'accueil sera affichée.

Accédez à / Remember-me / foo après vous être connecté avec Remember-Me.

spring-security.jpg

La page s'affiche normalement. Allez ensuite dans / Remember-me / high-level

spring-security.jpg

Cette fois, vous serez redirigé vers la page de connexion. Ceci est dû au fait que «/ Remember-me / high-level» est défini sur «FullyAuthenticated», c'est-à-dire que seule une connexion complète avec un mot de passe peut être affichée.

Entrez votre mot de passe pour vous connecter.

spring-security.jpg

Cette fois, / Remember-me / high-level s'affiche correctement.

Spring Security contrôle automatiquement la destination de la transition après la connexion pour être l'URL à laquelle vous tentiez d'accéder avant de vous connecter, donc aucun paramètre spécial n'est requis (n'importe quelle URL peut être spécifiée).

Détecter qu'un cookie a été volé

Avec le mécanisme Remember-Me par défaut décrit ci-dessus, il n'est pas possible de déterminer si un cookie a été volé par un tiers. Par conséquent, la victime ne remarque pas qu'elle a été endommagée et donne à l'attaquant une marge de manœuvre pour faire ce qu'il veut.

Par conséquent, Spring Security fournit un mécanisme qui peut détecter si un cookie a été volé afin de minimiser les dommages.

Mécanisme pour détecter les vols

Spring Security réalise le mécanisme de détection de vol en adoptant le mécanisme expliqué dans l'article ici.

En gros, la gestion des cookies est la suivante.

spring-security.jpg

Le contenu du cookie est "série" et "jeton". Et le serveur enregistre la combinaison des deux.

Au moment de la connexion automatique, la «série» extraite du cookie est recherchée pour le «jeton» enregistré par le serveur, et il est vérifié s'il correspond au «jeton» dans le cookie.

La connexion automatique est effectuée uniquement si les «jetons» correspondent, après quoi les «jetons» sont remplacés par de nouvelles valeurs.

Ce mécanisme d'utilisation de la «série» qui réutilise des valeurs comme identifiant qui identifie le cookie et de mise à jour du «jeton» chaque fois qu'une connexion automatique est effectuée est un mécanisme de détection de vol.

Si un attaquant se connecte automatiquement avec un cookie volé, le «token» contenu dans le cookie de l'attaquant et le «token» enregistré par le serveur sont mis à jour, mais le «token» du cookie de la victime est mis à jour. Restera vieux.

Par conséquent, si la victime tente de se connecter automatiquement après une connexion non autorisée, le «jeton» enregistré côté serveur et le «jeton» détenu par le cookie de la victime ne correspondront pas.

spring-security.jpg

Cela permettra au serveur de détecter que le cookie a peut-être été volé et d'en informer la victime ou l'administrateur du service.

C'est mon opinion personnelle, mais je pense que plus le délai d'expiration de la session est court, plus tôt le vol peut être détecté. Cependant, dans ce cas, les délais de session se produiront fréquemment et vous devrez entrer le mot de passe chaque fois que vous essayez d'ouvrir un écran qui nécessite une connexion complète comme décrit ci-dessus, et je pense que la convivialité diminuera. (Cela dépend si vous accordez la priorité à la sécurité ou à la facilité d'utilisation).

Les chaînes de caractères aléatoires générées à l'aide de «SecureRandom» sont utilisées pour «série» et «jeton».

Activer le mécanisme de détection de vol dans Spring Security

build.gradle


dependencies {
    compile 'org.springframework.security:spring-security-web:4.2.1.RELEASE'
    compile 'org.springframework.security:spring-security-config:4.2.1.RELEASE'
    compile 'org.springframework:spring-jdbc:4.3.7.RELEASE' ★
}

Ajout de spring-jdbc aux dépendances.

namespace

applicationContext.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:sec="http://www.springframework.org/schema/security"
       ...>
    
    ...
    
    <bean id="rememberMeTokenRepository"
          class="org.springframework.security.web.authentication.rememberme.InMemoryTokenRepositoryImpl" />
    
    <sec:http>
        ...
        <sec:remember-me token-repository-ref="rememberMeTokenRepository" />
    </sec:http>
    
    ...
</beans>

ʻInMemoryTokenRepositoryImpl est ajouté à la définition du bean et spécifié dans token-repository-refde la balise`.

Java Configuration

python


package sample.spring.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
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.web.authentication.rememberme.InMemoryTokenRepositoryImpl;

import java.util.Collections;

@EnableWebSecurity
@ComponentScan
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/login").permitAll()
                .antMatchers("/remember-me/high-level").fullyAuthenticated()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .and()
                .rememberMe()
                .tokenRepository(new InMemoryTokenRepositoryImpl()); ★
    }
    
    ...
}

Passez une instance de ʻInMemoryTokenRepositoryImpl avec tokenRepository () `.

spring-security.jpg

Connectez-vous avec Remember-Me activé.

spring-security.jpg

Copiez la valeur du cookie émis.

spring-security.jpg

Ouvrez un autre navigateur et ajoutez "Remember-me" au cookie pour définir la valeur que vous venez de copier.

spring-security.jpg

Si vous accédez à la page d'accueil, vous pouvez vous connecter sans saisir de mot de passe (en cas d'attaque réussie).

Dans cet état, revenez au navigateur qui était à l'origine connecté avec le mot de passe normalement, supprimez JSESSIONID, puis accédez à la page d'accueil. (Reproduction de l'état où la victime a de nouveau accédé après l'expiration de la session)

spring-security.jpg

CookieTheftException est lancé et un écran d'erreur apparaît.

Par défaut, même si une exception signifiant le vol de cookies est lancée, elle ne semble pas être gérée et elle est traitée comme une erreur système. (Pour le moment, il a été détecté que le cookie a été volé)

Classes qui apparaissent

spring-security.png

Le processus Remember-Me est lancé par RememberMeAuthenticationFilter. S'il y a un accès dans l'état non authentifié, ce filtre délègue le processus d'authentification à RememberMeService.

RememberMeService a deux classes d'implémentation. TokenBasedRememberMeServices fournit une authentification Remember-Me en utilisant la méthode simple que nous avons vue dans le premier Hello World. D'autre part, PersistentTokenBasedRememberMeServices réalise Remember-Me par une méthode qui peut détecter le vol, qui sera décrite plus loin.

PersistentTokenBasedRememberMeServices délègue le stockage de" series "et" tokens "à" PersistentTokenRepository ", et" PersistentTokenRepository "a deux classes en fonction de la méthode de stockage spécifique. JdbcTokenRepositoryImpl enregistre les informations dans une table de la base de données et ʻInMemoryTokenRepositoryImpl` les enregistre en mémoire.

Si vous activez simplement Remember-Me, TokenBasedRememberMeServices est utilisé pour implémenter RememberMeService. Cependant, vous pouvez basculer l'implémentation de RememberMeService vers PersistentTokenBasedRememberMeServices en spécifiant PersistentTokenRepository dans token-repository-ref.

Gestion des erreurs lorsque le vol de cookies est détecté

Une CookieTheftException est lancée lorsqu'un vol de cookie est détecté. Cependant, lorsque vous essayez de gérer cette exception, il semble que cela ne puisse pas être réalisé avec l'API fournie par Spring Security.

La CookieTheftException lancée par PersistentTokenBasedRememberMeServices est une fois interceptée par ʻAbstractRememberMeServices`. Ensuite, une fois le cookie effacé, il sera à nouveau lancé.

Après cela, il ne sera attrapé nulle part et volera vers le servlet.

Par conséquent, si vous essayez de gérer cette exception, vous n'avez pas d'autre choix que d'utiliser le mécanisme de gestion des exceptions standard Servlet.

web.xml


<?xml version="1.0" encoding="UTF-8"?>
<web-app ...>
    
    ...
    
    <error-page>
        <exception-type>org.springframework.security.web.authentication.rememberme.CookieTheftException</exception-type>
        <location>/cookie-theft.html</location>
    </error-page>
</web-app>

cookie-theft.html


<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>CookieTheftException</title>
    </head>
    <body>
        <h1>Le cookie a été volé!</h1>
    </body>
</html>

Si vous opérez pour que CookieTheftException soit lancé, l'écran d'erreur de la trace de pile ne sera pas affiché et vous passerez à l'écran suivant.

spring-security.jpg

Le servlet peut définir la destination de la transition lorsqu'une erreur se produit dans web.xml avec la balise <error-page>, alors utilisez ceci. Dans le cas de l'exemple ci-dessus, seules les pages statiques peuvent être affichées, mais le traitement dynamique peut être inséré en combinant avec Servlet.

web.xml


<?xml version="1.0" encoding="UTF-8"?>
<web-app ...>
    
    ...
    
    <error-page>
        <exception-type>org.springframework.security.web.authentication.rememberme.CookieTheftException</exception-type>
        <location>/cookie-theft</location>
    </error-page>
</web-app>

CookieTheftServlet.java


package sample.spring.security.servlet;

import org.springframework.security.web.authentication.rememberme.CookieTheftException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/cookie-theft")
public class CookieTheftServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        CookieTheftException e = (CookieTheftException)req.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
        try (PrintWriter writer = resp.getWriter()) {
            writer.println(e.getMessage());
        }
    }
}

État lorsqu'une erreur est générée spring-security.jpg

Assurez-vous que le servlet accepte le chemin spécifié par <location> '' de <page d'erreur> . Dans ce servlet, vous pouvez faire référence aux informations d'erreur telles que les objets d'exception en utilisant getAttribute ()deHttpServletRequest`.

Je ne l'ai pas essayé, mais si vous utilisez Spring MVC, je pense que vous pouvez le faire accepter par le contrôleur MVC.

Dans tous les cas, cela vous permet d'effectuer un traitement arbitraire, vous pouvez donc envoyer des informations d'erreur par e-mail.

Enregistrer dans la base de données

build.gradle


dependencies {
    compile 'org.springframework.security:spring-security-web:4.2.1.RELEASE'
    compile 'org.springframework.security:spring-security-config:4.2.1.RELEASE'
    compile 'org.springframework:spring-jdbc:4.3.7.RELEASE'
    compile 'com.h2database:h2:1.4.193'
}

Pour la base de données, utilisez H2 de la base de données intégrée pour le moment.

src/main/resources/sql/create_remember-me_tables.sql


CREATE TABLE PERSISTENT_LOGINS (
    USERNAME  VARCHAR(64) NOT NULL,
    SERIES    VARCHAR(64) NOT NULL PRIMARY KEY,
    TOKEN     VARCHAR(64) NOT NULL,
    LAST_USED TIMESTAMP   NOT NULL
);

Un fichier SQL qui crée une table pour enregistrer les informations de jeton.

namespace

applicationContext.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:sec="http://www.springframework.org/schema/security"
       xmlns:jdbc="http://www.springframework.org/schema/jdbc"
       ...
       xsi:schemaLocation="
         ...
         http://www.springframework.org/schema/jdbc
         http://www.springframework.org/schema/jdbc/spring-jdbc.xsd">
    
    ...
    
    <jdbc:embedded-database id="dataSource" type="H2">
        <jdbc:script location="classpath:/sql/create_remember-me_tables.sql" />
    </jdbc:embedded-database>
    
    <sec:http>
        <sec:intercept-url pattern="/login" access="permitAll" />
        <sec:intercept-url pattern="/remember-me/high-level" access="isFullyAuthenticated()" />
        <sec:intercept-url pattern="/**" access="isAuthenticated()" />
        <sec:form-login />
        <sec:logout />
        <sec:remember-me data-source-ref="dataSource" />
    </sec:http>
    
    ...
</beans>

Définissez la source de données comme un bean et spécifiez-la dans l'attribut data-source-ref de la balise <remember-me>.

Java Configuration

python


package sample.spring.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
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.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;
import java.util.Collections;

@EnableWebSecurity
@ComponentScan
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/login").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .and()
                .rememberMe()
                .tokenRepository(this.createTokenRepository());
    }
    
    public PersistentTokenRepository createTokenRepository() {
        DataSource dataSource =
                new EmbeddedDatabaseBuilder()
                    .generateUniqueName(true)
                    .setType(EmbeddedDatabaseType.H2)
                    .setScriptEncoding("UTF-8")
                    .addScript("/sql/create_remember-me_tables.sql")
                    .build();

        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
        
        return tokenRepository;
    }
    
    ...
}

La configuration Java ne semble pas avoir de méthode pour spécifier directement DataSource, alors définissez DataSource sur JdbcTokenRepositoryImpl puis passez-le avec la méthodetokenRepository ().

Personnalisez la table qui stocke les jetons

Comme j'ai vu l'implémentation, il semble impossible de personnaliser le nom de la table et le nom de la colonne uniquement avec l'implémentation standard. L'implémentation de JdbcTokenRepositoryImpl ressemble à ceci:

JdbcTokenRepositoryImpl.java


public class JdbcTokenRepositoryImpl extends JdbcDaoSupport implements
		PersistentTokenRepository {
	// ~ Static fields/initializers
	// =====================================================================================

	/** Default SQL for creating the database table to store the tokens */
	public static final String CREATE_TABLE_SQL = "create table persistent_logins (username varchar(64) not null, series varchar(64) primary key, "
			+ "token varchar(64) not null, last_used timestamp not null)";
	/** The default SQL used by the <tt>getTokenBySeries</tt> query */
	public static final String DEF_TOKEN_BY_SERIES_SQL = "select username,series,token,last_used from persistent_logins where series = ?";
	/** The default SQL used by <tt>createNewToken</tt> */
	public static final String DEF_INSERT_TOKEN_SQL = "insert into persistent_logins (username, series, token, last_used) values(?,?,?,?)";
	/** The default SQL used by <tt>updateToken</tt> */
	public static final String DEF_UPDATE_TOKEN_SQL = "update persistent_logins set token = ?, last_used = ? where series = ?";
	/** The default SQL used by <tt>removeUserTokens</tt> */
	public static final String DEF_REMOVE_USER_TOKENS_SQL = "delete from persistent_logins where username = ?";

	// ~ Instance fields
	// ================================================================================================

	private String tokensBySeriesSql = DEF_TOKEN_BY_SERIES_SQL;
	private String insertTokenSql = DEF_INSERT_TOKEN_SQL;
	private String updateTokenSql = DEF_UPDATE_TOKEN_SQL;
	private String removeUserTokensSql = DEF_REMOVE_USER_TOKENS_SQL;

        ...

Le texte SQL est défini dans le champ public static` et est défini dans le champ lors de l'instanciation. Le SQL défini dans ce champ est utilisé lors de la recherche de jetons, mais il n'existe aucune méthode pour réécrire ce champ. Il semble donc qu'il ne peut pas être réécrit (sérieusement? Quelque chose ne va pas?).

Si vous êtes un adulte et que vous ne pouvez pas spécifier le nom de la table ou le nom de la colonne, vous devrez peut-être copier JdbcTokenRepositoryImpl pour créer votre propreTokenRepository.

référence

Recommended Posts

Mémo d'utilisation de Spring Security Remember-Me
Mémo d'utilisation de Spring Security CSRF
Mémo d'utilisation de Spring Security Run-As
Spring Security Usage Memo Method Security
Mémo d'utilisation de Spring Security CORS
Test de mémo d'utilisation de Spring Security
Authentification / autorisation de mémo d'utilisation de Spring Security
En-tête de réponse de mémo d'utilisation de Spring Security
Gestion des sessions de mémo d'utilisation de Spring Security
Mémo d'utilisation de Spring Security Basic / mécanisme
Spring Security Usage Memo Domain Object Security (ACL)
Notes d'utilisation de Spring Shell
Notes d'utilisation de JavaParser
Notes d'utilisation de WatchService
Mémo d'utilisation PlantUML
Notes d'utilisation de JUnit5
Mémo JJUG CCC Printemps 2018
À propos de l'authentification Spring Security
Rédaction de mémo de démarrage de printemps (1)
Spring Security soulève 403 interdits
Rédaction de mémos de démarrage de printemps (2)
[Notes personnelles] À propos du framework Spring
Mémo de participation au printemps JJUG CCC 2018
Série de mémos d'auto-apprentissage Spring Framework_1
Fonction de connexion avec Spring Security
[Spring Security] Spring Security sur GAE (SE)
Notes sur l'utilisation du plug-in de gestion des dépendances
Essayez d'utiliser Spring Boot Security
Mémo de méthode de contrôleur de démarrage à ressort
Mise en œuvre de la fonction d'authentification avec Spring Security ②
◆ Spring Boot + note de construction de l'environnement gradle
Mémo d'utilisation de JCA (Java Encryption Architecture)
Implémentez la fonction d'authentification avec Spring Security ③
Tutoriel Spring Boot à l'aide de l'authentification Spring Security
cadre de printemps Mémo d'étude simple (2): AOP
Mise en œuvre de la fonction d'authentification avec Spring Security ①
Découvrez l'architecture de traitement de l'authentification Spring Security
Mémo après le premier projet Spring-MVC-
Un mémo qui a touché Spring Boot
Mémo de mise à niveau de la version d'introduction approfondie du printemps
Certification / autorisation avec Spring Security & Thymeleaf
Mémo après le premier projet Spring-Database-
Comment utiliser Thymeleaf avec Spring Boot
Développement d'applications Web Spring 5 MVC avec Visual Studio Code Utilisation de Spring Security 1/3 [Préparation]