[JAVA] Authentification / autorisation de mémo d'utilisation de Spring Security

Histoire de base et systématique Histoire Remember-Me 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

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

Authentification

UserDetailsService: Rechercher des informations utilisateur

ʻUserDetailsService` est responsable de la récupération des informations utilisateur.

Spring Security fournit plusieurs classes qui implémentent ʻUserDetailsService`.

En mémoire

Implémentation qui enregistre les informations utilisateur en mémoire. La classe spécifique est ʻInMemoryUserDetailsManager`.

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"
       ...>

    ...

    <sec:authentication-manager>
        <sec:authentication-provider>
            <sec:user-service>
                <sec:user name="hoge" password="HOGE" authorities="ROLE_USER" />
            </sec:user-service>
        </sec:authentication-provider>
    </sec:authentication-manager>
</beans>

Java Configuration

MySpringSecurityConfig.java


package sample.spring.security;

import org.springframework.beans.factory.annotation.Autowired;
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;

@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        ...
    }

    @Autowired
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("hoge").password("HOGE").roles("USER");
    }
}

--Déclarez une méthode dans la classe de configuration qui reçoit ʻAuthenticationManagerBuilder et annotez avec @ Autowired. --ʻInMemoryAuthentication () Définit les informations de définition avec la méthode.

JDBC Une implémentation qui récupère les informations utilisateur de la base de données. La classe réelle sera JdbcUserDetailsManager.

** Commun **

build.gradle (dépendance supplémentaire)


    compile 'org.springframework:spring-jdbc:4.3.6.RELEASE'
    compile 'com.h2database:h2:1.4.193'

--Pour la vérification, utilisez H2 pour DB en mode intégré.

src/main/resources/sql/create_database.sql


CREATE TABLE USERS (
    USERNAME VARCHAR_IGNORECASE(50) NOT NULL PRIMARY KEY,
    PASSWORD VARCHAR_IGNORECASE(50) NOT NULL,
    ENABLED  BOOLEAN NOT NULL
);

CREATE TABLE AUTHORITIES (
    USERNAME  VARCHAR_IGNORECASE(50) NOT NULL,
    AUTHORITY VARCHAR_IGNORECASE(50) NOT NULL,
    CONSTRAINT FK_AUTHORITIES_USERS FOREIGN KEY (USERNAME) REFERENCES USERS(USERNAME),
    CONSTRAINT UK_AUTHORITIES UNIQUE (USERNAME, AUTHORITY)
);

INSERT INTO USERS VALUES ('fuga', 'FUGA', true);
INSERT INTO AUTHORITIES VALUES ('fuga', 'USER');

--Par défaut, si vous déclarez une colonne de table comme décrit ci-dessus, les informations utilisateur seront recherchées automatiquement. --Il peut être modifié par réglage.

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"
       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_database.sql" />
    </jdbc:embedded-database>
    
    <sec:authentication-manager>
        <sec:authentication-provider>
            <sec:jdbc-user-service data-source-ref="dataSource"  />
        </sec:authentication-provider>
    </sec:authentication-manager>
</beans>

--Utilisez la balise . --Dans la définition de la source de données, le script d'initialisation écrit ci-dessus est exécuté à l'aide de la balise <jdbc: script>.

Java Configuration

MySpringSecurityConfig.java


package sample.spring.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
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 javax.sql.DataSource;

@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        ...
    }
    
    @Bean
    public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder()
                .generateUniqueName(true)
                .setType(EmbeddedDatabaseType.H2)
                .setScriptEncoding("UTF-8")
                .addScript("/sql/create_database.sql")
                .build();
    }

    @Autowired
    public void configure(AuthenticationManagerBuilder auth, DataSource dataSource) throws Exception {
        auth.jdbcAuthentication().dataSource(dataSource);
    }
}

--Utilisez la méthode jdbcAuthentication () de ʻAuthenticationManagerBuilder`.

Ajuster les noms de table et de colonne

CREATE TABLE USERS (
    LOGIN_ID VARCHAR_IGNORECASE(50) NOT NULL PRIMARY KEY,
    PASSWORD VARCHAR_IGNORECASE(50) NOT NULL,
    ENABLED  BOOLEAN NOT NULL
);

CREATE TABLE AUTHORITIES (
    LOGIN_ID  VARCHAR_IGNORECASE(50) NOT NULL,
    ROLE VARCHAR_IGNORECASE(50) NOT NULL,
    CONSTRAINT FK_AUTHORITIES_USERS FOREIGN KEY (LOGIN_ID) REFERENCES USERS(LOGIN_ID),
    CONSTRAINT UK_AUTHORITIES UNIQUE (LOGIN_ID, ROLE)
);

Essayez de changer ʻUSERNAME en LOGIN_ID et ʻAUTHORITY en ROLE.

Si vous souhaitez modifier le nom de la table ou le nom de la colonne comme vous le souhaitez, ajustez le SQL lors de la recherche d'informations utilisateur. Le nom de la colonne peut être n'importe quoi tant que l'ordre des éléments au moment de la recherche correspond.

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"
       xmlns:jdbc="http://www.springframework.org/schema/jdbc"
       ...>

    ...
    
    <sec:authentication-manager>
        <sec:authentication-provider>
            <sec:jdbc-user-service
                data-source-ref="dataSource"
                users-by-username-query="SELECT LOGIN_ID, PASSWORD, ENABLED FROM USERS WHERE LOGIN_ID=?"
                authorities-by-username-query="SELECT LOGIN_ID, ROLE FROM AUTHORITIES WHERE LOGIN_ID=?" />
        </sec:authentication-provider>
    </sec:authentication-manager>
</beans>

--Dans l'attribut ʻusers-by-username-query, définissez une requête pour rechercher ʻUSERNAME, PASSWORD, ʻENABLED. --Dans l'attribut ʻauthorities-by-username-query, définissez une requête pour rechercher ʻUSERNAME, ʻAUTHORITY.

Java Configuration

MySpringSecurityConfig.java


package sample.spring.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
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 javax.sql.DataSource;

@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        ...
    }
    
    @Bean
    public DataSource dataSource() {
        ...
    }

    @Autowired
    public void configure(AuthenticationManagerBuilder auth, DataSource dataSource) throws Exception {
        auth.jdbcAuthentication().dataSource(dataSource)
        .usersByUsernameQuery("SELECT LOGIN_ID, PASSWORD, ENABLED FROM USERS WHERE LOGIN_ID=?")
        .authoritiesByUsernameQuery("SELECT LOGIN_ID, ROLE FROM AUTHORITIES WHERE LOGIN_ID=?");
    }
}

--Définissez une requête pour rechercher ʻUSERNAME, PASSWORD, ʻENABLED dans la méthode ʻusersByUsernameQuery (String). --Définissez une requête pour rechercher ʻUSERNAME, ʻAUTHORITYdans la méthode ʻauthoritiesByUsernameQuery (String).

Créez votre propre UserDetailsService

MyUserDetailsService.java


package sample.spring.security;

import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

public class MyUserDetailsService implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if ("hoge".equals(username)) {
            return new User(username, "HOGE", AuthorityUtils.createAuthorityList("USER"));
        }
        
        throw new UsernameNotFoundException("not found : " + username);
    }
}

--ʻCréez une classe qui implémente UserDetailsService. --ʻUserDetailsService n'a qu'une seule méthode appelée loadUserByUsername (String). --Une chaîne de caractères pour identifier l'utilisateur (généralement le nom d'utilisateur saisi sur l'écran de connexion, etc.) est transmise en tant qu'argument, de sorte que les informations utilisateur correspondant à cette chaîne de caractères d'identification sont renvoyées. --Throw ʻUsernameNotFoundException` si les informations utilisateur correspondantes n'existent pas.

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="myUserDetailsService" class="sample.spring.security.MyUserDetailsService" />
    
    <sec:authentication-manager>
        <sec:authentication-provider user-service-ref="myUserDetailsService" />
    </sec:authentication-manager>
</beans>

--Spécifiez ʻUserDetailsService créé avec l'attribut ʻuser-service-ref de<authentication-provider>.

Java Configuration

MySpringSecurityConfig.java


package sample.spring.security;

import org.springframework.beans.factory.annotation.Autowired;
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;

@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {

    ...
    
    @Autowired
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(new MyUserDetailsService());
    }
}

Hachage de mot de passe

Pourquoi le hachage est nécessaire

Dans le cas peu probable où des données seraient divulguées, il est mal conditionné que le mot de passe soit stocké en texte brut.

Par conséquent, le mot de passe est généralement enregistré dans une base de données ou similaire sous une forme dans laquelle la chaîne de caractères d'origine ne peut pas être spécifiée. Si vous n'avez pas besoin de combiner les mots de passe, utilisez une fonction de hachage pour convertir le mot de passe.

BCrypt En parlant de fonctions de hachage, il existe MD5 et SHA, mais si vous souhaitez hacher les mots de passe, il semble préférable d'utiliser BCrypt.

Si vous appliquez simplement la fonction de hachage une seule fois, [attaque de mot de passe] telle qu'une attaque circulaire, une attaque par dictionnaire, une table arc-en-ciel, etc. (https://ja.wikipedia.org/wiki/%E3%83%91%E3% 82% B9% E3% 83% AF% E3% 83% BC% E3% 83% 89% E3% 82% AF% E3% 83% A9% E3% 83% 83% E3% 82% AF) devenir.

BCrypt rend difficile de deviner le mot de passe d'origine en appliquant un sel aléatoire, puis en appliquant le hachage plusieurs fois au lieu de simplement hacher l'entrée une fois.

Spring Security recommande également d'utiliser ce BCrypt.

la mise en oeuvre

Le hachage de mot de passe peut être réalisé en définissant PasswordEncoder sur DaoAuthenticationProvider. Lorsque vous utilisez BCrypt, utilisez l'implémentation PasswordEncoder``` BCryptPasswordEncoder.

En outre, la valeur de hachage est décrite à l'avance par BCrypt hash value calcul | tekboy.

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="passwordEncoder"
          class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
    
    <sec:authentication-manager>
        <sec:authentication-provider>
            <sec:user-service>
                <sec:user
                    name="hoge"
                    password="$2a$08$CekzJRYhb5bzp5mx/eZmX.grG92fRXo267QVVyRs0IE.V.zeCIw8S"
                    authorities="ROLE_USER" />
            </sec:user-service>
            
            <sec:password-encoder ref="passwordEncoder" />
        </sec:authentication-provider>
    </sec:authentication-manager>
</beans>

--Définissez BCryptPasswordEncoder comme bean et spécifiez-le dans l'attribut ref de<password-encoder>. --Définissez <password-encoder> comme élément enfant de <authentication-provider>.

Java Configuration

MySpringSecurityConfig.java


package sample.spring.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
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 org.springframework.security.crypto.password.PasswordEncoder;

@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {

    ...
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Autowired
    public void configure(AuthenticationManagerBuilder auth, PasswordEncoder passwordEncoder) throws Exception {
        auth.inMemoryAuthentication()
            .passwordEncoder(passwordEncoder)
            .withUser("hoge")
            .password("$2a$08$CekzJRYhb5bzp5mx/eZmX.grG92fRXo267QVVyRs0IE.V.zeCIw8S")
            .roles("USER");
    }
}

Encoder le mot de passe

Pour encoder n'importe quel mot de passe, saisissez simplement PasswordEncoder dans le conteneur et utilisez la méthode ʻencode ()`.

EncodePasswordServlet.java


package sample.spring.security.servlet;

import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

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;

@WebServlet("/encode-password")
public class EncodePasswordServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(req.getServletContext());
        PasswordEncoder passwordEncoder = context.getBean(PasswordEncoder.class);

        String password = req.getParameter("password");
        String encode = passwordEncoder.encode(password);
        System.out.println(encode);
    }
}

Une fois connecté, accédez à http: // localhost: 8080 / xxxx / encode-password? Password = fuga (remplacez le chemin de contexte selon le cas).

Sortie de la console du serveur


$2a$10$2qVDkAqxp8eDrxR8Be2ZpubYGOCVZ7Qy9uK/XzOIY1ZoxpChtrWDK

Authentication ʻAuthentication` existe dans l'une des classes importantes qui composent Spring Security. Cette classe stocke des informations sur les utilisateurs authentifiés (tels que les noms d'utilisateur et une liste des autorisations accordées).

Si l'authentification par ʻAuthenticationProvider réussit, ʻAuthenticationProvider crée et retourne un objet ʻAuthenticationauthentifié (ʻisAuthenticated ()retourne true). Après cela, cet objet authentifié «Authentification» sera référencé dans un traitement ultérieur tel que la vérification des autorisations.

Comment obtenir l'authentification et les informations disponibles

SecurityContextHolderSampleServlet.java


package sample.spring.security.servlet;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetails;

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 static java.util.stream.Collectors.*;

@WebServlet("/authentication")
public class SecurityContextHolderSampleServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        System.out.println("[authorities]");
        System.out.println("  " + auth.getAuthorities().stream()
                                    .map(GrantedAuthority::getAuthority)
                                    .collect(joining("\n  ")));

        WebAuthenticationDetails details = (WebAuthenticationDetails) auth.getDetails();
        System.out.println("[details]");
        System.out.println("  IP Address : " + details.getRemoteAddress());
        System.out.println("  Session ID : " + details.getSessionId());

        UserDetails principal = (UserDetails) auth.getPrincipal();
        System.out.println("[principal]");
        System.out.println("  username : " + principal.getUsername());
        System.out.println("  password : " + principal.getPassword());

        System.out.println("[credentials]");
        System.out.println("  " + auth.getCredentials());
    }
}

Résultat d'exécution


[authorities]
  USER
[details]
  IP Address : 0:0:0:0:0:0:0:1
  Session ID : 0225051BCDFE2C34D55DF4FA9D9685C2
[principal]
  username : hoge
  password : null
[credentials]
  null

Pour des raisons de sécurité, les informations de mot de passe sont explicitement supprimées (définies sur null) par ʻAuthenticationManager ( ProviderManager) après une connexion réussie. Il est également possible de ne pas l'effacer avec l'option (ʻeraseCredentialsAfterAuthentication).

Emplacement de stockage d'authentification

Authenticationの保存場所.png

Le SecurityContext qui contient ʻAuthentication est sauvegardé dans HttpSession` par défaut une fois l'authentification terminée.

La prochaine fois qu'il est accédé dans la même session, le SecurityContext stocké dans HttpSession sera récupéré et stocké dans SecurityContextHolder.

Ce SecurityContextHolder utilise ThreadLocal par défaut pour stocker SecurityContext dans le champ static. Par conséquent, le SecurityContext associé à la requête actuelle peut être obtenu globalement.

Strictement parlant, SecurityContextHolder contient une instance de SecurityContextHolderStrategy, et l'implémentation de cette interface est ThreadLocalSecurityContextHolderStrategy, qui stocke SecurityContext dans ThreadLocal.

À propos, SecurityContextPersistenceFilter effectue le chargement et le déchargement de SecurityContext vers SecurityContextHolder et l'effacement de ThreadLocal pour chaque requête.

Méthode d'enregistrement autre que ThreadLocal

En plus de ThreadLocalSecurityContextHolderStrategy, il existe deux classes restantes dans l'implémentation de SecurityContextHolderStrategy.

GlobalSecurityContextHolderStrategy

Enregistrez un seul «SecurityContext» dans votre application.

Cette classe est utilisée, par exemple, dans une application autonome. Pour les applications autonomes, l'utilisateur en cours d'exécution peut être le seul utilisateur. Dans ce cas, même si vous créez plusieurs threads, vous devrez peut-être partager les mêmes informations d'identification pour tous.

InheritableThreadLocalSecurityContextHolderStrategy

Lorsqu'un nouveau thread est créé, il partage le SecurityContext du thread parent.

Cette classe peut être utilisée par plusieurs utilisateurs, mais elle est utilisée lorsqu'un nouveau thread est créé dans le traitement de chaque utilisateur pour exécuter le traitement en arrière-plan. Dans ce cas, les threads sont séparés, mais les informations d'identification doivent hériter des informations utilisateur du thread parent.

La méthode de stockage utilisée peut être modifiée par l'une des méthodes suivantes.

** Spécifié dans les propriétés système **

Il peut être spécifié en passant la propriété système spring.security.strategy aux options de démarrage de la JVM.

Lors de la spécification au démarrage de Tomcat


> set JAVA_OPTS=-Dspring.security.strategy=MODE_INHERITABLETHREADLOCAL

> cd %TOMCAT_HOME%\bin

> startup.bat

** Précisez avec la méthode statique **

python


SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);

SecurityContextHolder fournit une méthode appelée setStrategyName (String). Pour l'argument, spécifiez également la constante définie dans SecurityContextHolder.

Spécifiez la page de connexion

Si vous activez la connexion par formulaire mais ne spécifiez pas de page de connexion, la page de connexion simple générée par Spring Security est utilisée par défaut.

spring-security.jpg

Ceci est juste un écran pour vérifier l'opération, et dans l'application réelle, il est nécessaire de le remplacer par la page de connexion créée par vous-même.

Modifiez la page de connexion comme suit.

la mise en oeuvre

my-login.jsp


<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!doctype html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>My Login Page</title>
    </head>
    <body>
        <h1>My Login Page</h1>
        
        <c:url var="loginUrl" value="/login" />
        <form action="${loginUrl}" method="post">
            <div>
                <label>Nom d'utilisateur: <input type="text" name="username" /></label>
            </div>
            <div>
                <label>mot de passe: <input type="password" name="password" /></label>
            </div>
            <input type="submit" value="login" />
            <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
        </form>
    </body>
</html>

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="/my-login.jsp" access="permitAll" />
        <sec:intercept-url pattern="/**" access="isAuthenticated()" />
        <sec:form-login login-page="/my-login.jsp" />
        <sec:logout />
    </sec:http>

    ...
</beans>

Java Configuration

MySpringSecurityConfig.java


...

@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/login").permitAll()
                .antMatchers("/my-login.jsp").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin().loginPage("/my-login.jsp");
    }

    ...
}

Contrôle de fonctionnement

spring-security.jpg

Si vous essayez d'accéder à une page, vous serez redirigé vers votre propre page de connexion.

La description

applicationContext.xml


        <sec:intercept-url pattern="/login" access="permitAll" />
        <sec:intercept-url pattern="/my-login.jsp" access="permitAll" />
        <sec:intercept-url pattern="/**" access="isAuthenticated()" />
        <sec:form-login login-page="/my-login.jsp" />

my-login.jsp


        <c:url var="loginUrl" value="/login" />
        <form action="${loginUrl}" method="post">
            <div>
                <label>Nom d'utilisateur: <input type="text" name="username" /></label>
            </div>
            <div>
                <label>mot de passe: <input type="password" name="password" /></label>
            </div>
            <input type="submit" value="login" />
            <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
        </form>

--Une demande de connexion peut être faite à / login avec la méthode POST.

Spécifiez la page après la connexion

Par défaut, la destination de la transition après la connexion est contrôlée comme suit.

  1. Si vous avez accédé à une URL avant de vous connecter, redirigez-la vers elle
  2. Si vous ouvrez directement la page de connexion et que vous vous connectez, redirigez vers la racine de l'application (/) (cible par défaut)

la mise en oeuvre

hello.html


<!doctype html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>Hello</title>
    </head>
    <body>
        <h1>Hello!!</h1>
    </body>
</html>

Ajoutez un écran simple.

Contrôle de fonctionnement

spring-security.jpg

Accédez à / hello.html.

spring-security.jpg

Vous serez redirigé vers l'écran de connexion, alors connectez-vous.

spring-security.jpg

Vous serez redirigé vers la page (/ hello.html) à laquelle vous accédiez avant de vous connecter.

Ensuite, déconnectez-vous une fois, puis accédez directement à la page de connexion (/ login).

spring-security.jpg

s'identifier.

spring-security.jpg

Il est ignoré à la racine de l'application (/).

Changer la cible par défaut

Vous pouvez changer la destination de la transition après avoir ouvert la page de connexion directement et vous être connecté avec default-target-url

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"
       ...>
    
    <sec:http>
        <sec:intercept-url pattern="/login" access="permitAll" />
        <sec:intercept-url pattern="/**" access="isAuthenticated()" />
        <sec:form-login default-target-url="/hello.html" />
        <sec:logout />
    </sec:http>

    ...
</beans>

--Spécifié par default-target-url

Java Configuration

MySpringSecurityConfig.java


...

@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/login").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin().defaultSuccessUrl("/hello.html");
    }

    ...
}

--Spécifié par defaultSuccessUrl (String)

Contrôle de fonctionnement

Accédez directement à l'écran de connexion (/ login).

spring-security.jpg

s'identifier

spring-security.jpg

Vous serez passé à l'URL (/ hello.html) spécifiée par default-target-url.

Toujours passer à la cible par défaut

Même s'il y a une page à laquelle vous avez essayé d'accéder avant de vous connecter, modifiez-la pour qu'elle passe à la cible par défaut après la connexion.

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"
       ...>
    
    <sec:http>
        <sec:intercept-url pattern="/login" access="permitAll" />
        <sec:intercept-url pattern="/**" access="isAuthenticated()" />
        <sec:form-login default-target-url="/hello.html"
                        always-use-default-target="true" />
        <sec:logout />
    </sec:http>

    ...
</beans>

--Spécifiez true pour ʻalways-use-default-target`

Java Configuration

MySpringSecurityConfig


...

@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/login").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin().defaultSuccessUrl("/hello.html", true);
    }

    ...
}

--Spécifiez true comme deuxième argument de defaultSuccessUrl (String, boolean)

Contrôle de fonctionnement

spring-security.jpg

Accédez à l'URL appropriée.

spring-security.jpg

Vous serez redirigé vers l'écran de connexion, alors connectez-vous.

spring-security.jpg

Vous serez renvoyé à la page spécifiée par default-target-url.

Mettre en œuvre le processus lorsque la connexion est réussie

la mise en oeuvre

MyAuthenticationSuccessHandler.java


package sample.spring.security.handler;

import org.springframework.security.core.Authentication;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    
    @Override
    public void onAuthenticationSuccess(
            HttpServletRequest request, HttpServletResponse response, Authentication authentication)
                throws IOException, ServletException {
        RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
        redirectStrategy.sendRedirect(request, response, "/hello.html");
    }
}

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="authenticationSuccessHandler"
          class="sample.spring.security.handler.MyAuthenticationSuccessHandler" />
    
    <sec:http>
        ...
        <sec:form-login authentication-success-handler-ref="authenticationSuccessHandler" />
        ...
    </sec:http>

    ...
</beans>

--Spécifiez le bean du ʻAuthenticationSuccessHandler créé dans l'attribut ʻauthentication-success-handler-ref de la balise<form-login>.

Java Configuration

MySpringSecurityConfig.java


...

import sample.spring.security.handler.MyAuthenticationSuccessHandler;

@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                ...
                .and()
                .formLogin().successHandler(new MyAuthenticationSuccessHandler());
    }

    ...
}

--Spécifiez une instance de ʻAuthenticationSuccessHandler créée par la méthode successHandler () `

L'état de fonctionnement est omis car il ne redirige que vers / hello.html.

Lorsqu'il est spécifié en même temps que la cible par défaut

Si vous spécifiez la cible par défaut et ʻAuthenticationSuccessHandler` en même temps, cela fonctionne comme suit.

L'espace de noms est priorisé pour déterminer les paramètres, mais la configuration Java écrase les paramètres lorsque la méthode est appelée, donc cette différence est faite.

Mettre en œuvre le processus lorsque la connexion échoue

MyAuthenticationFailureHandler.java


package sample.spring.security.handler;

import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
    
    @Override
    public void onAuthenticationFailure(
            HttpServletRequest request, HttpServletResponse response, AuthenticationException exception)
                throws IOException, ServletException {
        DefaultRedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
        redirectStrategy.sendRedirect(request, response, "/login");
    }
}

--Créez une classe qui implémente ʻAuthenticationFailureHandler`

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="authenticationFailureHandler"
          class="sample.spring.security.handler.MyAuthenticationFailureHandler" />
    
    <sec:http>
        ...
        <sec:form-login authentication-failure-handler-ref="authenticationFailureHandler"/>
        ...
    </sec:http>

    ...
</beans>

--Spécifiez le bean du ʻAuthenticationFailureHandler créé avec ʻauthentication-failure-handler-ref de<form-login>.

Java Configuration

MySpringSecurityConfig.java


...

import sample.spring.security.handler.MyAuthenticationFailureHandler;

@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/login").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                    .failureHandler(new MyAuthenticationFailureHandler());
    }

    ...
}

--Spécifiez un gestionnaire avec failureHandler ()

L'opération est omise car elle revient simplement à l'écran de connexion.

Identifiez la cause de l'échec de connexion

ʻOnAuthenticationFailure () de ʻAuthenticationFailureHandler peut recevoir l'exception qui s'est produite lors de l'authentification à la fin de l'argument. En examinant cette exception, la cause de l'échec de connexion peut être identifiée.

Si vous souhaitez ajuster le message d'erreur lorsque le compte est verrouillé, je pense que vous pouvez le contrôler ici.

exception situation
BadCredentialsException L'utilisateur n'existe pas, le mot de passe est incorrect, etc.
LockedException UserDetails.isAccountNonLocked()MaisfalseRevenu
DisabledException UserDetails.isEnabled()MaisfalseRevenu
AccountExpiredException UserDetails.isAccountNonExpired()MaisfalseRevenu
CredentialsExpiredException UserDetails.isCredentialsNonExpired()MaisfalseRevenu
SessionAuthenticationException Lorsque le nombre de sessions dépasse la limite supérieure (Détails à une date ultérieure

Autorisation

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"
       ...>

    ...

    <sec:http>
        <sec:intercept-url pattern="/login" access="permitAll" />
        <sec:intercept-url pattern="/**" access="isAuthenticated() and hasAuthority('USER')" />
        <sec:form-login />
        <sec:logout />
    </sec:http>
    
    <sec:authentication-manager>
        <sec:authentication-provider>
            <sec:user-service>
                <sec:user
                    name="hoge"
                    password="hoge"
                    authorities="USER" />
                <sec:user
                    name="fuga"
                    password="fuga"
                    authorities="" />
            </sec:user-service>
        </sec:authentication-provider>
    </sec:authentication-manager>
</beans>

Java Configuration

MySpringSecurityConfig.java


package sample.spring.security;

import org.springframework.beans.factory.annotation.Autowired;
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
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/login").permitAll()
                .anyRequest().access("isAuthenticated() and hasAuthority('USER')")
                .and()
                .formLogin();
    }
    
    @Autowired
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("hoge")
            .password("hoge")
            .authorities("USER")
            .and()
            .withUser("fuga")
            .password("fuga")
            .authorities(Collections.emptyList());
    }
}

Contrôle de fonctionnement

spring-security.jpg

Connectez-vous en tant qu'utilisateur hoge

spring-security.jpg

La première page peut être affichée.

spring-security.jpg

Puis connectez-vous en tant qu'utilisateur fuga

spring-security.jpg

403 J'obtiens une erreur.

La description

applicationContext.xml


    <sec:http>
        <sec:intercept-url pattern="/login" access="permitAll" />
        <sec:intercept-url pattern="/**" access="isAuthenticated() and hasAuthority('USER')" />
        <sec:form-login />
        <sec:logout />
    </sec:http>

--Définissez les conditions requises pour l'accès avec l'attribut ʻaccess de `. --SpEL (Spring Expression Language), qui est le propre langage d'expression de Spring, est utilisé pour cette condition.

applicationContext.xml


    <sec:user
        name="hoge"
        password="hoge"
        authorities="USER" />
    <sec:user
        name="fuga"
        password="fuga"
        authorities="" />

--ʻLa chaîne de caractères spécifiée dans l'attribut des autoritésdevient l'autorité de l'utilisateur. --Si vous en spécifiez plusieurs, séparez-les par, (exemple: ʻUTILISATEUR, ADMIN).

Comment ça fonctionne

Moment d'exécution du processus d'autorisation

認可処理のタイミング.png

Le processus d'autorisation basé sur l'URL est effectué à la fin de la série de processus "Filtre". Cela est fait par ʻAccessDecisionManager dans le processus de FilterSecurityInterceptor`.

Jugement par vote

L'implémentation de ʻAccessDecisionManager` fournie par Spring Security en standard détermine la disponibilité de l'accès par ** "vote" **.

La classe d'implémentation de ʻAccessDecisionManager peut avoir plusieurs classes de vote appelées ʻAccessDecisionVoter. Ensuite, chaque ʻAccessDecisionVoter est fait pour vérifier (voter) si l'utilisateur actuel a ou non les droits d'accès à la cible (objet sécurisé). Le résultat du vote sera l'un des suivants: "accorder (ʻACCESS_GRANTED)", "rejet (ʻACCESS_DENIED)" et "retrait (ʻACCESS_ABSTAIN)". La classe d'implémentation de ʻAccessDecisionManager regroupe les résultats de vote de ʻAccessDecisionVoter et décide de l'accès final.

認可処理の流れ.png

Il existe trois classes d'implémentation de ʻAccessDecisionManager, ʻAffirmativeBased, ConsensusBased et ʻUnanimousBased`, selon la méthode d'agrégation.

La valeur par défaut est ʻAffirmativeBased`.

Comment déterminer les droits d'accès

«Les trois classes d'implémentation par défaut d'AccessDecisionManager» ne déterminent pas directement la présence ou l'absence de droits d'accès. C'est la classe d'électeurs qui implémente l'interface ʻAccessDecisionVoter` qui détermine en fait la présence ou l'absence de droits d'accès.

L'interface ʻAccessDecisionVoter` est définie comme suit (seulement certains).

AccessDecisionVoter


package org.springframework.security.access;

import java.util.Collection;

import org.springframework.security.core.Authentication;

public interface AccessDecisionVoter<S> {
	int ACCESS_GRANTED = 1;
	int ACCESS_ABSTAIN = 0;
	int ACCESS_DENIED = -1;

	...

	int vote(Authentication authentication, S object, Collection<ConfigAttribute> attributes);

}

Il existe une méthode pour voter «vote ()». Cette méthode détermine l'existence d'un droit d'accès à partir des informations de l'argument reçu, et retourne l'une des constantes (ʻACCESS_GRANTED, ʻACCESS_ABSTAIN, ʻACCESS_DENIED) également définies dans ʻAccessDecisionVoter.

Chaque argument a la signification suivante.

La classe d'implémentation de ʻAccessDecisionVoter obtient les privilèges accordés à l'utilisateur à partir de ʻauthentication. Ensuite, on évalue si l'utilisateur a ou non les droits d'accès en comparant avec le paramètre de sécurité passé dans «attributs».

Implémentation d'AccessDecisionVoter

Si true est spécifié dans l'attribut ʻuse-expressions de la balise (la valeur par défaut est true), WebExpressionVoter est utilisé pour implémenter ʻAccessDecisionVoter.

Cette classe est une expression, un électeur qui évalue une expression (SpEL) pour déterminer l'accès.

ʻAccessDecisionVoter a également RoleVoteretPreInvocationAuthorizationAdviceVoter` utilisés dans la sécurité des méthodes.

Autorité accordée, qui représente l'autorité de l'utilisateur

L'interface ʻAuthentication définit une méthode appelée getAuthorities () . Cette méthode retourne une collection de GrantedAuthority`.

GrantedAuthority est aussi une interface, comme son nom l'indique " permissions accordées à l'utilisateur ". GrantedAuthority n'a qu'une seule méthode définie qui renvoie String appeléegetAuthority (). Cette méthode est conçue pour renvoyer "une représentation sous forme de chaîne des autorisations représentées par une instance de" GrantedAuthority "" [^ 2]. En bref, c'est une chaîne de caractères qui représente une telle autorité, telle que «ROLE_USER» ou «OP_REGISTER_ITEM».

[^ 2]: De par sa conception, si l'autorité ne peut pas être exprimée par une simple chaîne de caractères, «null» est renvoyé. Cependant, l'implémentation standard (telle que SimpleGrantedAuthority) renvoie essentiellement une chaîne de caractères, donc l'explication de ce cas est omise ici.

Dans Hello World, la valeur définie dans l'attribut ʻauthorities de la balise est GrantedAuthority`.

applicationContext.xml


<sec:user
    name="hoge"
    password="hoge"
    authorities="USER" />★ Ce

Les informations d'autorisation définies ici sont initialement stockées dans la classe qui implémente ʻUserDetets. Ensuite, lorsque le processus d'authentification est effectué par ʻAuthenticationProvider, il est acquis par la méthodegetAuthorities ()de ʻUserDetails et stocké dans l'instance ʻAuthentication.

Résumé du mécanisme

認可仕組みまとめ.png

--FilterSecurityInterceptor indique à ʻAccessDecisionManager (ʻAffirmativeBased) de déterminer le droit d'accès. --ʻAffirmativeBased délègue la détermination des droits d'accès à ʻAccessDecisionVoter (WebExpressionVoter). --WebExpressionVoter obtient une collection de GrantedAuthority de ʻAuthentication. --WebExpressionVoter exécute l'expression conditionnelle (SpEL) à partir des informations d'argument et des informations GrantedAuthority`.

Contrôle d'accès basé sur les expressions

Si WebExpressionVoter est utilisé pour implémenter ʻAccessDecisionVoter, le contrôle d'accès basé sur l'expression peut être défini dans l'attribut ʻaccess de la balise <intercept-url>.

Spring Expression Language (SpEL) est utilisé pour les expressions utilisées ici. Spring Security a été étendu pour vous permettre d'utiliser vos propres fonctions et variables afin de faciliter la définition des contrôles d'accès.

Écrivez cette expression pour qu'elle soit finalement évaluée à un seul booléen. Ensuite, si le résultat de l'évaluation de l'expression est «vrai», l'accès est autorisé, et s'il est «faux», l'accès est refusé.

Fonctions / variables disponibles </ span>

Fonctions / variables Vérifier le contenu / les valeurs Exemple
hasRole(String) A le rôle spécifié hasRole('USER')
hasAnyRole(String...) A l'un des rôles spécifiés hasAnyRole('FOO', 'ROLE_BAR')
hasAuthority(String) Avoir l'autorité spécifiée hasAuthority('CREATE_TICKET')
hasAnyAuthority(String...) Avoir l'une des autorisations spécifiées hasAnyAuthority('CREATE_TICKET', 'MANAGE_TICKET')
isAnonymous() Être authentifié de manière anonyme -
isRememberMe() Remember-Moi certifié -
isAuthenticated() Doit être certifié -
isFullyAuthenticated() Soyez entièrement authentifié -
permitAll toujourstrueEst évalué comme -
denyAll toujoursfalseEst évalué comme -

La relation entre ʻisAnonymous () , ʻisRememberMe (), ʻisAuthenticated () , ʻisFullyAuthenticated () est la suivante.

Authentification anonyme Remember-Certification moi Certification complète[^3]
isAnonymous() true false false
isRememberMe() false true false
isAuthenticated() false true true
isFullyAuthenticated() false false true

[^ 3]: Identifiants (mot de passe, etc.) vérifiés avec succès et authentifiés garantis (en bref, après vous être connecté normalement à Form)

Différence entre hasRole () et hasAuthority ()

Parmi les fonctions qui peuvent être utilisées avec WebExpressionVoter, il y a hasRole () ʻet hasAuthority () ʻen tant que fonctions pour vérifier l'autorisation. Les deux ne changent pas le point de vérification de l'existence de «GrantedAuthority» donné à l'utilisateur.

La différence est que «hasRole ()» complète le préfixe «ROLE_».

Droits des utilisateurs → USER ROLE_USER
hasRole('USER') false true
hasRole('ROLE_USER') false true
hasAuthority('USER') true false
hasAuthority('ROLE_USER') false true

hasAuthority () vérifie que la représentation sous forme de chaîne de GrantedAuthority correspond exactement.

D'un autre côté, hasRole () complète ROLE_ et le compare avec GrantedAuthority si la chaîne passée en argument ne commence pas par ROLE_. (HasRole ('USER') complète ROLE_ et se compare à ROLE_USER)

Qu'est-ce que ROLE?

Quelle est la différence entre le rôle et l'autorité? Rien ne change. La seule différence est de savoir s'il commence par «ROLE_» ou non, les deux étant en fait «GrantedAuthority».

La raison pour laquelle celui avec le préfixe ROLE_ est traité spécialement est que ** c'est ma supposition **, mais cela est dû au fait que Voter appelé RoleVoter a été utilisé dans le passé. Je ressens.

«WebExpressionVoter» a été ajouté à la version 3.0, et avant cela, il semble que la combinaison de ** peut-être ** «RoleVoter» et «AuthenticatedVoter» ait été utilisée.

Si vous utilisez un espace de noms, vous pouvez le faire en définissant ʻuse-expression dans sur false`.

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"
       ...>
    
    <sec:http use-expressions="false">
        <sec:intercept-url pattern="/login" access="IS_AUTHENTICATED_ANONYMOUSLY" />
        <sec:intercept-url pattern="/**" access="ROLE_ADMIN" />
        <sec:form-login />
        <sec:logout />
    </sec:http>
    
    <sec:authentication-manager>
        <sec:authentication-provider>
            <sec:user-service>
                <sec:user
                    name="user"
                    password="user"
                    authorities="ROLE_USER" />
                <sec:user
                    name="admin"
                    password="admin"
                    authorities="ROLE_ADMIN" />
            </sec:user-service>
        </sec:authentication-provider>
    </sec:authentication-manager>
</beans>

SpEL ne peut pas être utilisé pour ʻaccès de . Au lieu de cela, écrivez les paramètres pour ʻAuthenticatedVoter et RoleVoter.

ʻIS_AUTHENTICATED_ANONYMOUSLY est un paramètre pour ʻAuthenticatedVoter pour vérifier l'authentification anonyme (c'est-à-dire que c'est OK même si vous ne vous êtes pas connecté).

De plus, ROLE_ADMIN vérifie si le paramètre de RoleVoter a l'autorité ROLE_ADMIN.

Puisque pattern =" / login " n'a que le paramètre pour ʻAuthenticatedVoter, la vérification par RoleVoter est inutile. Cependant, ʻAccessDecisionManager ne peut pas juger si c'est nécessaire ou non [^ 4], donc pour le moment, chaque ʻAccessDecisionVoter est invité à voter (ici, ʻAuthenticatedVoter et RoleVoter sont Voter).

[^ 4]: ʻAccessDecisionManager ne sait pas (ne sait pas) si la classe réelle derrière l'interface ʻAccessDecisionVoter est RoleVoter

Que ce soit nécessaire ou non est déterminé par la méthode «supports (ConfigAttribute)» de chaque «électeur». Voici la méthode «supports ()» de «RoleVoter».

RoleVoter soutient()Méthode


    public boolean supports(ConfigAttribute attribute) {
        if ((attribute.getAttribute() != null)
                && attribute.getAttribute().startsWith(getRolePrefix())) {
            return true;
        }
        else {
            return false;
        }
    }

Pour ʻattribute, la valeur spécifiée par l'attribut ʻaccess est passée (si plusieurs sont spécifiés séparés par des virgules, ils sont passés un par un). getRolePrefix () retourne"ROLE_".

En d'autres termes, il vérifie si la valeur spécifiée par l'attribut ʻaccess commence par ROLE_`, et si elle démarre, elle la prend en charge, sinon elle ne la prend pas en charge. S'il n'est pas pris en charge, «RoleVoter» renverra un «retrait» à la suite du vote.

De cette façon, en faisant commencer le nom de l'autorisation par ROLE_, RoleVoter n'effectuera pas de traitement de vérification d'autorisation inutile. De même, ʻAuthenticatedVoter ne traite pas à moins que la valeur spécifiée par ʻaccess soit une chaîne de caractères spécifique. En d'autres termes, les valeurs de définition commençant par «ROLE_» ne sont pas prises en charge et ne sont pas traitées.

De cette manière, chaque «électeur» contrôle la présence ou l'absence de soutien afin qu'aucun jugement inutile ne soit émis. Le résultat est un préfixe spécial appelé «ROLE_».

Cependant, maintenant que «WebExpressionVoter» est apparu, il est devenu possible de définir de manière flexible avec SpEL, et je pense que le besoin de combiner plusieurs «Voter» a diminué. (En fait, même si vous essayez de combiner WebExpressionVoter et RoleVoter, si vous écrivez ʻaccess =" ROLE_USER "`, une erreur se produira lors de l'analyse de l'expression SpEL, et vous ne pourrez pas les combiner en premier lieu.)

Se référer au bean de l'expression SpEL

la mise en oeuvre

MyExpression.java


package sample.spring.security.expression;

import org.springframework.security.core.Authentication;

public class MyExpression {

    public boolean check(Authentication authentication) {
        String name = authentication.getName();
        System.out.println("name = " + name);
        return "hoge".equals(name);
    }
}

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="myExpression" class="sample.spring.security.expression.MyExpression" />
    
    <sec:http>
        <sec:intercept-url pattern="/login" access="permitAll" />
        <sec:intercept-url pattern="/**" access="@myExpression.check(authentication)" />
        <sec:form-login />
        <sec:logout />
    </sec:http>

    <sec:authentication-manager>
        <sec:authentication-provider>
            <sec:user-service>
                <sec:user
                        name="hoge"
                        password="hoge"
                        authorities="" />
                <sec:user
                        name="fuga"
                        password="fuga"
                        authorities="" />
            </sec:user-service>
        </sec:authentication-provider>
    </sec:authentication-manager>
</beans>

Java Configuration

MySpringSecurityConfig.java


package sample.spring.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
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 sample.spring.security.expression.MyExpression;

import java.util.Collections;

@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/login").permitAll()
                .anyRequest().access("@myExpression.check(authentication)")
                .and()
                .formLogin();
    }

    @Autowired
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("hoge")
                .password("hoge")
                .authorities(Collections.emptyList())
                .and()
                .withUser("fuga")
                .password("fuga")
                .authorities(Collections.emptyList());
    }
    
    @Bean
    public MyExpression myExpression() {
        return new MyExpression();
    }
}

Contrôle de fonctionnement

Lors de l'accès par hoge sur la gauche, lors de l'accès par fuga sur la droite

spring-security.jpg

Journal du serveur


name = hoge
name = fuga

La description

MyExpression.java


package sample.spring.security.expression;

import org.springframework.security.core.Authentication;

public class MyExpression {

    public boolean check(Authentication authentication) {
        String name = authentication.getName();
        System.out.println("name = " + name);
        return "hoge".equals(name);
    }
}

applicationContext.xml


    <sec:http>
        ...
        <sec:intercept-url pattern="/**" access="@myExpression.check(authentication)" />
        ...
    </sec:http>

Objets pour lesquels des constantes et des fonctions sont définies

Pour permitAll et hasAuthority (), [SecurityExpressionRoot](http://docs.spring.io/autorepo/docs/spring-security/4.2.x-SNAPSHOT/apidocs/org/springframework/security/access/ Il est défini dans expression / SecurityExpressionRoot.html).

En outre, lorsque le contrôle d'accès à Filter est traité, [WebSecurityExpressionRoot](http://docs.spring.io/autorepo/docs/spring-security/4.2.x-SNAPSHOT/apidocs/org/springframework/security/ web / access / expression / WebSecurityExpressionRoot.html) est utilisé.

Utilisez votre propre électeur

la mise en oeuvre

AcceptFugaVoter.java


package sample.spring.security.voter;

import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;

public class AcceptFugaVoter implements AccessDecisionVoter<Object> {
    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }

    @Override
    public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
        Object principal = authentication.getPrincipal();
        if (!(principal instanceof UserDetails)) {
            return ACCESS_ABSTAIN;
        }

        String username = ((UserDetails)principal).getUsername();
        return "fuga".equals(username) ? ACCESS_GRANTED : ACCESS_DENIED;
    }
}

Un électeur bâclé qui autorise l'accès si le nom d'utilisateur est «fuga».

namespace

application.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="accessDecisionManager"
          class="org.springframework.security.access.vote.AffirmativeBased">
        <constructor-arg>
            <list>
                <bean class="org.springframework.security.web.access.expression.WebExpressionVoter" />
                <bean class="sample.spring.security.voter.AcceptFugaVoter" />
            </list>
        </constructor-arg>
    </bean>
    
    <sec:http access-decision-manager-ref="accessDecisionManager">
        <sec:intercept-url pattern="/login" access="permitAll" />
        <sec:intercept-url pattern="/**" access="hasAuthority('HOGE')" />
        <sec:form-login />
        <sec:logout />
    </sec:http>
    
    <sec:authentication-manager>
        <sec:authentication-provider>
            <sec:user-service>
                <sec:user
                    name="hoge"
                    password="hoge"
                    authorities="HOGE" />
                <sec:user
                    name="fuga"
                    password="fuga"
                    authorities="" />
                <sec:user
                    name="piyo"
                    password="piyo"
                    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.security.access.AccessDecisionManager;
import org.springframework.security.access.vote.AffirmativeBased;
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.access.expression.WebExpressionVoter;
import sample.spring.security.voter.AcceptFugaVoter;

import java.util.Arrays;
import java.util.Collections;

@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .accessDecisionManager(this.createAccessDecisionManager())
                .antMatchers("/login").permitAll()
                .anyRequest().hasAuthority("HOGE")
                .and()
                .formLogin();
    }
    
    private AccessDecisionManager createAccessDecisionManager() {
        return new AffirmativeBased(Arrays.asList(
            new WebExpressionVoter(),
            new AcceptFugaVoter()
        ));
    }
    
    @Autowired
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("hoge")
            .password("hoge")
            .authorities("HOGE")
        .and()
            .withUser("fuga")
            .password("fuga")
            .authorities(Collections.emptyList())
        .and()
            .withUser("piyo")
            .password("piyo")
            .authorities(Collections.emptyList());
    }
}

Contrôle de fonctionnement

De gauche à droite, l'état après la connexion en tant qu'utilisateur hoge, fuga, piyo.

spring-security.jpg

La description

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="accessDecisionManager"
          class="org.springframework.security.access.vote.AffirmativeBased">
        <constructor-arg>
            <list>
                <bean class="org.springframework.security.web.access.expression.WebExpressionVoter" />
                <bean class="sample.spring.security.voter.AcceptFugaVoter" />
            </list>
        </constructor-arg>
    </bean>
    
    <sec:http access-decision-manager-ref="accessDecisionManager">
        ...
    </sec:http>
    
    ...
</beans>

Héritage des rôles

Le rôle a une relation d'héritage

Le rôle a généralement une relation d'héritage.

Par exemple, s'il existe des rôles pour «utilisateur» et «administrateur», «administrateur» hérite généralement de «utilisateur». En d'autres termes, ce qu'un «utilisateur» peut faire peut également être fait par un «administrateur».

Cependant, si vous essayez de contrôler cela simplement avec ou sans rôle, les paramètres seront les suivants.

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"
       ...>
    
    <sec:http>
        <sec:intercept-url pattern="/login" access="permitAll" />
        <sec:intercept-url pattern="/hierarchy/admin" access="hasRole('ADMIN')" />
        <sec:intercept-url pattern="/hierarchy/user" access="hasRole('USER') or hasRole('ADMIN')" />
        <sec:intercept-url pattern="/**" access="isAuthenticated()" />
        <sec:form-login />
        <sec:logout />
    </sec:http>
    
    <sec:authentication-manager>
        <sec:authentication-provider>
            <sec:user-service>
                <sec:user
                    name="user"
                    password="user"
                    authorities="ROLE_USER" />
                <sec:user
                    name="admin"
                    password="admin"
                    authorities="ROLE_ADMIN" />
            </sec:user-service>
        </sec:authentication-provider>
    </sec:authentication-manager>
</beans>

/ hierarchy / admin n'est accessible qu'à l '" administrateur ", et / hierarchy / user est accessible à l'" utilisateur ".

Pour / hierarchy / admin, simplement hasRole ('ADMIN'). Cependant, / hierarchy / user est hasRole ('USER') ou hasRole ('ADMIN'). Si seul hasRole ('USER') est utilisé, il se bloquera lors de l'accès par un utilisateur qui n'a que ROLE_ADMIN, il s'agit donc d'un paramètre redondant.

De cette façon, si vous essayez de réaliser la relation d'héritage du rôle simplement avec ou sans rôle, définissez le rôle enfant (ROLE_ADMIN) dans tous les endroits où le rôle parent ( ROLE_USER) est spécifié. Tu vas devoir.

Il existe également un moyen de définir ʻaccess uniquement sur hasRole ('USER') , et de définir ʻADMIN sur ʻauthorities, ainsi que de définir ʻUSER. Cependant, dans tous les cas, il n'y a aucune différence en ce que la description est redondante.

Définir l'héritage de rôle à l'aide de RoleHierarchy

Spring Security fournit un mécanisme pour définir les relations d'héritage des rôles.

Le paramètre précédent peut être réécrit comme suit en utilisant RoleHierarchy.

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"
       ...>

    <bean id="roleHierarchy"
          class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
        <property name="hierarchy">
            <value>
                ROLE_ADMIN > ROLE_USER
            </value>
        </property>
    </bean>
    
    <bean id="expressionHandler"
          class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler">
        <property name="roleHierarchy" ref="roleHierarchy" />
    </bean>
    
    <sec:http>
        <sec:expression-handler ref="expressionHandler" />
        
        <sec:intercept-url pattern="/login" access="permitAll" />
        <sec:intercept-url pattern="/hierarchy/admin" access="hasRole('ADMIN')" />
        <sec:intercept-url pattern="/hierarchy/user" access="hasRole('USER')" />
        <sec:intercept-url pattern="/**" access="isAuthenticated()" />
        <sec:form-login />
        <sec:logout />
    </sec:http>
    
    <sec:authentication-manager>
        <sec:authentication-provider>
            <sec:user-service>
                <sec:user
                    name="user"
                    password="user"
                    authorities="ROLE_USER" />
                <sec:user
                    name="admin"
                    password="admin"
                    authorities="ROLE_ADMIN" />
            </sec:user-service>
        </sec:authentication-provider>
    </sec:authentication-manager>
</beans>

Java Configuration

MySpringSecurityConfig.java


package sample.spring.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
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.FilterInvocation;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;

@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .expressionHandler(this.createSecurityExpressionHandler())
                .antMatchers("/login").permitAll()
                .antMatchers("/hierarchy/user").hasRole("USER")
                .antMatchers("/hierarchy/admin").hasRole("ADMIN")
                .anyRequest().authenticated()
                .and()
                .formLogin();
    }
    
    private SecurityExpressionHandler<FilterInvocation> createSecurityExpressionHandler() {
        RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
        roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER");

        DefaultWebSecurityExpressionHandler expressionHandler = new DefaultWebSecurityExpressionHandler();
        expressionHandler.setRoleHierarchy(roleHierarchy);
        
        return expressionHandler;
    }
    
    @Autowired
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("user")
            .password("user")
            .roles("USER")
        .and()
            .withUser("admin")
            .password("admin")
            .roles("ADMIN");
    }
}

Contrôle de fonctionnement

Connectez-vous en tant que ʻuser et ʻadmin pour accéder respectivement à / hierarchy / user et à / hierarchy / admin.

** Lorsque vous êtes connecté en tant qu'utilisateur **

spring-security.jpg

** Si vous vous connectez en tant qu'administrateur **

spring-security.jpg

La description

Définition de RoleHierarchyImpl


    <bean id="roleHierarchy"
          class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
        <property name="hierarchy">
            <value>
                ROLE_ADMIN > ROLE_USER
            </value>
        </property>
    </bean>

Lors de la définition de plus d'un

ROLE_A > ROLE_B
ROLE_B > ROLE_C

Vous pouvez le faire comme ceci (il n'y a pas besoin de sauts de ligne, mais c'est plus facile à voir).

Définissez RoleHierarchyImpl à utiliser dans l'évaluation des expressions


    <bean id="roleHierarchy"
          class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
        ...
    </bean>
    
    <bean id="expressionHandler"
          class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler">
        <property name="roleHierarchy" ref="roleHierarchy" />
    </bean>
    
    <sec:http>
        <sec:expression-handler ref="expressionHandler" />
        
        ...
    </sec:http>

Ensuite, définissez cette RoleHierarchyImpl à utiliser lorsque la SpEL est évaluée.

Pour ce faire, enregistrez SecurityExpressionHandler en tant que bean. Utilisez DefaultWebSecurityExpressionHandler comme classe d'implémentation et spécifiez le RoleHierarchyImpl défini précédemment dans la propriété roleHierarchy.

Ajoutez ensuite «» comme sous-élément de «» et spécifiez «SecurityExpressionHandler» dans l'attribut «ref».

N'utilisez pas WebExpressionVoter

Utilisez RoleHierarchyVoter sans utiliser WebExpressionVoter.

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"
       ...>

    <bean id="roleHierarchy"
          class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
        <property name="hierarchy">
            <value>
                ROLE_ADMIN > ROLE_USER
            </value>
        </property>
    </bean>
    
    <bean id="roleHierarchyVoter"
          class="org.springframework.security.access.vote.RoleHierarchyVoter">
        <constructor-arg ref="roleHierarchy" />
    </bean>
    
    <bean id="accessDecisionManager"
          class="org.springframework.security.access.vote.AffirmativeBased">
        <constructor-arg>
            <list>
                <bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
                <ref bean="roleHierarchyVoter" />
            </list>
        </constructor-arg>
    </bean>
    
    <sec:http use-expressions="false"
              access-decision-manager-ref="accessDecisionManager">
        <sec:intercept-url pattern="/login" access="IS_AUTHENTICATED_ANONYMOUSLY" />
        <sec:intercept-url pattern="/hierarchy/admin" access="ROLE_ADMIN" />
        <sec:intercept-url pattern="/hierarchy/user" access="ROLE_USER" />
        <sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
        <sec:form-login />
        <sec:logout />
    </sec:http>
    
    <sec:authentication-manager>
        <sec:authentication-provider>
            <sec:user-service>
                <sec:user
                    name="user"
                    password="user"
                    authorities="ROLE_USER" />
                <sec:user
                    name="admin"
                    password="admin"
                    authorities="ROLE_ADMIN" />
            </sec:user-service>
        </sec:authentication-provider>
    </sec:authentication-manager>
</beans>

Contrôle au moment de l'erreur d'autorisation

Spécifiez la page d'erreur

la mise en oeuvre

access-denied.html


<!doctype html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>Erreur d'autorisation</title>
    </head>
    <body>
        <h1>L'opération n'est pas autorisée!</h1>
    </body>
</html>

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="/test" access="hasAuthority('HOGE')" />
        <sec:intercept-url pattern="/**" access="isAuthenticated()" />
        <sec:form-login />
        <sec:logout />
        <sec:access-denied-handler error-page="/access-denied.html" />
    </sec:http>

    ...
</beans>

Java Configuration

MySpringSecurityConfig.java


...

@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                ...
                .and()
                .exceptionHandling().accessDeniedPage("/access-denied.html");
    }

    ...
}

Contrôle de fonctionnement

Après vous être connecté avec hoge, accédez à / test

spring-security.jpg

La description

applicationContext.xml


<sec:access-denied-handler error-page="/access-denied.html" />

MySpringSecurityConfig.java


.exceptionHandling().accessDeniedPage("/access-denied.html");

--Pour l'espace de noms, ajoutez la balise <access-denied-handler> et spécifiez-la avec l'attribut ʻerror-page. --Pour la configuration Java, spécifiez avec ʻexceptionHandler (). AccessDeniedPage (String)

Contrôle avec implémentation arbitraire

la mise en oeuvre

MyAccessDeniedHandler.java


package sample.spring.security.handler;

import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.access.AccessDeniedHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyAccessDeniedHandler implements AccessDeniedHandler {
    
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        if (response.isCommitted()) {
            return;
        }
        
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);

        DefaultRedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
        redirectStrategy.sendRedirect(request, response, "/access-denied.html");
    }
}

--Créez une classe qui implémente AccessDeniedHandler et implémentez le traitement au moment de l'erreur d'autorisation dans la méthode handle ().

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="accessDeniedHandler"
          class="sample.spring.security.handler.MyAccessDeniedHandler" />
    
    <sec:http>
        ...
        <sec:access-denied-handler ref="accessDeniedHandler" />
    </sec:http>

    ...
</beans>

--Spécifiez le bean de ʻAccessDeniedHandler dans l'attribut refde`

Java Configuration

MySpringSecurityConfig.java


...

import sample.spring.security.handler.MyAccessDeniedHandler;

@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                ...
                .and()
                .exceptionHandling().accessDeniedHandler(new MyAccessDeniedHandler());
    }

    ...
}

Résultat d'exécution

Fonctionne de la même manière que lorsque ʻerror-page` a été spécifié.

spring-security.jpg

Vous pouvez maintenant voir que l'URL a changé et est maintenant une redirection.

référence

Recommended Posts

Authentification / autorisation de mémo d'utilisation de Spring Security
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 Remember-Me
Mémo d'utilisation de Spring Security CORS
Test 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
Certification / autorisation avec Spring Security & Thymeleaf
Spring Security Usage Memo Domain Object Security (ACL)
À propos de l'authentification Spring Security
Notes d'utilisation de Spring Shell
Mémo d'utilisation de Spring Security: coopération avec Spring MVC et Boot
Mise en œuvre de la fonction d'authentification avec Spring Security ②
Implémentez la fonction d'authentification avec Spring Security ③
Tutoriel Spring Boot à l'aide de l'authentification Spring Security
Mise en œuvre de la fonction d'authentification avec Spring Security ①
Découvrez l'architecture de traitement de l'authentification Spring Security
Définissez le résultat de l'authentification Spring Security sur JSON
Authentification DB avec Spring Security et hachage avec BCrypt
Obtenez une authentification BASIC avec Spring Boot + Spring Security
Mémo rétrospective du printemps
Notes d'utilisation de JavaParser
Notes d'utilisation de WatchService
Mémo d'utilisation PlantUML
Notes d'utilisation de JUnit5
Essayez l'authentification LDAP avec Spring Security (Spring Boot) + OpenLDAP
Ajoutez vos propres éléments d'authentification avec Spring Security
[Introduction à Spring Boot] Fonction d'authentification avec Spring Security
Mémo JJUG CCC Printemps 2018
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)
Créer une authentification par clé API pour l'API Web dans Spring Security
Un nouvel employé a tenté de créer une fonction d'authentification / autorisation à partir de zéro avec Spring Security
[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
Une erreur 404 se produit lors du test de l'authentification par formulaire avec Spring Security