[JAVA] Mémo d'utilisation de Spring Security CORS

Histoire de base et systématique Histoire de certification / autorisation Histoire Remember-Me Histoire CSRF Histoire de gestion de session Histoire de l'en-tête de la réponse Histoire de la sécurité de la méthode L'histoire de Run-As L'histoire d'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 CORS

Le [Résumé CORS --Qiita] de @ tomoyukilabs (http://qiita.com/tomoyukilabs/items/81698edd5812ff6acb34) a été une expérience d'apprentissage.

En gros résumé

C'est comme ressentir.

Qu'est-ce que "l'origine"Définition de l'origine|Même politique d'origine-Sécurité Web| MDNVoir.

Hello World

Préparation des pages pour l'accès avec l'origine croisée

Placez le code HTML suivant sur GitHub afin qu'il puisse être ouvert à partir du navigateur en tant que page statique.

python


<!doctype html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>cors test</title>
  </head>
  <body>
    <div>
      <select id="contextPath">
        <option value="namespace" selected>namespace</option>
        <option value="java-config">java-config</option>
      </select>
    </div>

    <div>
      <input id="headerName" placeholder="Header-Name" />
      <input id="headerValue" placeholder="Header-Value" />
    </div>

    <div>
      <input id="responseHeaderName" placeholder="responseHeaderName" />
    </div>

    <button type="button" id="sendButton">Send Request</button>

    <script src="https://code.jquery.com/jquery-3.2.1.min.js"
            integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
            crossorigin="anonymous"></script>

    <script>
      $(function() {
        $('#sendButton').on('click', function() {
          var headers = {};
          var headerName = $('#headerName').val();
          var headerValue = $('#headerValue').val();
          if (headerName) {
            headers[headerName] = headerValue;
          }

          var contextPath = $('#contextPath').val();

          $.ajax({
            url: 'http://localhost:8080/' + contextPath + '/cors',
            type: 'GET',
            dataType: 'text',
            headers: headers
          })
          .done(function(text, status, jqXhr) {
            console.log("text = " + text);

            var responseHeaderName = $('#responseHeaderName').val();
            if (responseHeaderName) {
              console.log("[ResponseHeader] " + responseHeaderName + " : " + jqXhr.getResponseHeader(responseHeaderName));
            }
          })
          .fail(function() {
            console.error(arguments);
          });
        });
      });
    </script>
  </body>
</html>

Celui qui a été publié sur GitHub

J'essaye d'accéder à localhost avec Ajax.

Implémentation côté serveur

CorsServlet.java


package sample.spring.security.servlet;

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("/cors")
public class CorsServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setHeader("Original-Header", "CORS!!");
        try (PrintWriter writer = resp.getWriter()) {
            writer.println("Hello CORS!!");
        }
    }
}

Une implémentation qui renvoie simplement l'en-tête et le corps du texte appropriés.

Tout d'abord, essayez d'accéder sans configurer CORS

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: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

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 {
        http.authorizeRequests()
                .antMatchers("/login").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin();
    }

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

Aucun réglage pour CORS n'a été effectué.

Lorsque je clique sur le bouton «Envoyer la demande» sur la page de vérification, j'obtiens l'erreur suivante: ..

spring-security.jpg

J'ai été bloqué par la vérification d'authentification de Spring Security et j'ai été redirigé vers la page de connexion.

Il indique également qu'il n'est pas accessible car l'en-tête ʻAccess-Control-Allow-Origin` défini dans la spécification CORS est absent de la réponse.

Modifiez les paramètres de Spring Security pour les rendre accessibles

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">
    
    <bean id="corsConfiguration" class="org.springframework.web.cors.CorsConfiguration">
        <property name="allowedOrigins">
            <list>
                <value>http://opengl-8080.github.io</value>
            </list>
        </property>
        <property name="allowedMethods">
            <list>
                <value>GET</value>
            </list>
        </property>
    </bean>

    <bean id="corsSource" class="org.springframework.web.cors.UrlBasedCorsConfigurationSource">
        <property name="corsConfigurations">
            <map>
                <entry key="/cors" value-ref="corsConfiguration" />
            </map>
        </property>
    </bean>
    
    <sec:http>
        <sec:intercept-url pattern="/login" access="permitAll" />
        <sec:intercept-url pattern="/cors" access="permitAll" />
        <sec:intercept-url pattern="/**" access="isAuthenticated()" />
        <sec:form-login />
        <sec:logout />
        <sec:cors configuration-source-ref="corsSource" />
    </sec:http>

    ...
</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 org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

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

    private CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedMethod("GET");
        corsConfiguration.addAllowedOrigin("http://opengl-8080.github.io");

        UrlBasedCorsConfigurationSource corsSource = new UrlBasedCorsConfigurationSource();
        corsSource.registerCorsConfiguration("/cors", corsConfiguration);

        return corsSource;
    }

    ...
}

Exécutez à nouveau.

spring-security.jpg

Cette fois, l'accès a réussi et le texte renvoyé par le serveur peut être sorti.

La description

Activer CORS

applicationContext.xml


    <bean id="corsSource" class="org.springframework.web.cors.UrlBasedCorsConfigurationSource">
        ...
    </bean>
    
    <sec:http>
        ...
        <sec:cors configuration-source-ref="corsSource" />
    </sec:http>

MySpringSecurityConfig.java


    @Override
    public void configure(HttpSecurity http) throws Exception {
        http...
                .and()
            .cors()
                .configurationSource(this.corsConfigurationSource());
    }

    private CorsConfigurationSource corsConfigurationSource() {
        ...
    }

--Pour la configuration Java, spécifiez avec .cors (). ConfigurationSource (CorsConfigurationSource)

Paramètres CORS

applicationContext.xml


    <bean id="corsConfiguration" class="org.springframework.web.cors.CorsConfiguration">
        <property name="allowedOrigins">
            <list>
                <value>http://opengl-8080.github.io</value>
            </list>
        </property>
        <property name="allowedMethods">
            <list>
                <value>GET</value>
            </list>
        </property>
    </bean>

    <bean id="corsSource" class="org.springframework.web.cors.UrlBasedCorsConfigurationSource">
        <property name="corsConfigurations">
            <map>
                <entry key="/cors" value-ref="corsConfiguration" />
            </map>
        </property>
    </bean>

--Utilisez deux classes pour configurer CORS --CorsConfigurationSource et CorsConfiguration

MySpringSecurityConfig.java


    private CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedMethod("GET");
        corsConfiguration.addAllowedOrigin("http://opengl-8080.github.io");

        UrlBasedCorsConfigurationSource corsSource = new UrlBasedCorsConfigurationSource();
        corsSource.registerCorsConfiguration("/cors", corsConfiguration);

        return corsSource;
    }

--Pour la configuration Java, vous pouvez utiliser des méthodes qui peuvent être définies une par une, telles que ʻaddAllowedMethod (String) et registerCorsConfiguration (String, CorsConfiguration) `.

Correspond à la demande de contrôle en amont

La spécification CORS limite les méthodes HTTP et les en-têtes configurables autorisés par défaut.

Si vous souhaitez envoyer un en-tête qui n'est pas autorisé par défaut, vous êtes censé envoyer une demande de pré-allumage, une demande de pré-allumage pour "vérifier si c'est autorisé".

Le client envoie la demande de production uniquement si le serveur renvoie "OK" à cette demande.

Essayez d'abord d'envoyer un en-tête HTTP qui n'est pas autorisé

spring-security.jpg

Essayez de soumettre une demande avec un en-tête non autorisé appelé «Hoge».

spring-security.jpg

J'étais très en colère.

Il indique qu'il n'est pas accessible car un en-tête n'était pas autorisé dans la demande de contrôle en amont.

Vérifiez les en-têtes de demande et de réponse.

spring-security.jpg

L'en-tête de la requête dit ʻAccess-Control-Request-Headers: hoge, et je vérifie si l'en-tête hoge` est autorisé. Cependant, la réponse n'a pas d'en-tête indiquant que «hoge» est autorisé.

Pour cette raison, le navigateur détermine que «hoge» est un en-tête non autorisé et suspend le traitement.

Autoriser les en-têtes Hoge

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="corsConfiguration" class="org.springframework.web.cors.CorsConfiguration">
        <property name="allowedOrigins">
            <list>
                <value>http://opengl-8080.github.io</value>
            </list>
        </property>
        <property name="allowedMethods">
            <list>
                <value>GET</value>
            </list>
        </property>
        <property name="allowedHeaders">★ Ajout
            <list>
                <value>Hoge</value>
            </list>
        </property>
    </bean>

    ...
</beans>

Java Configuration

MySpringSecurityConfig.java


package sample.spring.security;

...

@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
    
    ...

    private CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        ...
        corsConfiguration.addAllowedHeader("Hoge");★ Ajout

        ...
    }

    ...
}

Hoge est ajouté à ʻallowedHeader de CorsConfiguration`.

Vérifiez à nouveau l'opération.

spring-security.jpg

Cette fois, la demande est passée correctement.

Vérifiez l'état de la requête HTTP.

spring-security.jpg

La demande de contrôle en amont de la méthode ʻOPTIONSest exécutée en premier, puis la demande de la productionGET` est envoyée.

Jetez un œil à l'en-tête vers «OPTIONS».

spring-security.jpg

ʻAccess-Control-Allow-Headers: hogea été ajouté à l'en-tête de réponse pour indiquer que l'en-têtehoge` est autorisé.

Spring Security répond automatiquement aux demandes de contrôle en amont selon les règles d'autorisation définies dans CorsConfiguration.

Il existe des restrictions par défaut lorsque le client accède à n'importe quel en-tête de réponse, mais [ExposedHeaders](http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/cors/ Cela peut être autorisé en définissant CorsConfiguration.html # addExposedHeader-java.lang.String-).

référence

Recommended Posts

Mémo d'utilisation de Spring Security CORS
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
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
Mémo d'utilisation de Spring Security: coopération avec Spring MVC et Boot
Mémo rétrospective du printemps
Notes d'utilisation de JavaParser
Notes d'utilisation de WatchService
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
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
◆ 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