Skip to content

18. [Cours]: مدیریت دسترسی بین‌دامنه‌ای

واژه‌های کلیدی: CORS (اشتراک منابع فرا-منشأ).

این فصل تا حدودی از TD مستقل است. این بخش حفظ شده است زیرا مفاهیم برنامه‌نویسی وب و برنامه‌نویسی جاوااسکریپت را معرفی می‌کند. شایان ذکر است که یکی از اهداف این TD ارائه مفاهیم پرکاربرد در توسعه JEE، یعنی توسعه وب مبتنی بر فریم‌ورک‌های جاوا، است. در اینجا، ما وب‌سرور مورد استفاده در مطالعه پایگاه داده محصول و دسته‌بندی را ارتقا می‌دهیم تا بتواند درخواست‌های بین‌دامنه‌ای را بپذیرد.

در سند [Tutoriel AngularJS / Spring 4]، ما یک برنامهٔ کلاینت/سرور توسعه می‌دهیم که در آن کلاینت یک برنامهٔ AngularJS است:

  • صفحات HTML / CSS / JS از برنامه Angular توسط سرور [1] ارائه می‌شوند؛
  • در [2]، سرویس [dao] درخواستی به سرور دیگری، یعنی سرور [2]، ارسال می‌کند. با این حال، این کار توسط مرورگری که برنامه Angular را اجرا می‌کند ممنوع است، زیرا یک آسیب‌پذیری امنیتی محسوب می‌شود. این برنامه فقط می‌تواند از سروری که از آن منشأ گرفته است، یعنی سرور [1]، درخواست کند؛

در واقع، درست نیست که بگوییم مرورگر مانع از ارسال درخواست توسط برنامه Angular به سرور [2] می‌شود. در واقع، مرورگر یک درخواست ارسال می‌کند تا بپرسد آیا سرور به کلاینتی که از دامنهٔ خود آن نیست اجازه می‌دهد تا به آن درخواست ارسال کند. این تکنیک اشتراک‌گذاری با نام CORS (اشتراک‌گذاری منابع فرامنشأ) شناخته می‌شود. سرور [2] با ارسال هدرهای خاص HTTP اجازه را صادر می‌کند.

ما قصد داریم معماری زیر را ایجاد کنیم:

  • در [1]، یک برنامه وب صفحات HTML / jS را ارائه می‌دهد؛
  • در [2]، مرورگر جاوااسکریپت جاسازی‌شده در صفحات HTML را اجرا می‌کند تا از سرویس وب امن [3] پرس‌وجو کند؛

18.1. Support

  

پروژه‌های این فصل را می‌توان در پوشه [support / chap-18] یافت.

18.2. پروژهٔ مشتری

پروژهٔ زیر را در Eclipse ایجاد کنید:

  

18.3. پیکربندی Maven

این پروژه یک پروژه Maven است که شامل فایل زیر است: [pom.xml]:


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>istia.st.webjson</groupId>
    <artifactId>intro-server-webjson-01</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <name>intro-server-webjson-01</name>
    <description>démo spring mvc</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.7.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>istia.st.springdata</groupId>
            <artifactId>intro-spring-data-01</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.18.1</version>
            </plugin>
        </plugins>
    </build>

</project>
  • خطوط ۱۱–۱۵: این یک پروژه Spring Boot است؛
  • خطوط ۲۳–۲۶: وابستگی [spring-boot-starter-web] استفاده می‌شود که شامل سرور Tomcat و Spring MVC است؛

18.4. پیکربندی Spring

  

کلاس [WebConfig] که پروژه Spring را پیکربندی می‌کند، به شرح زیر است:


package spring.cors.client.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    // -------------------------------- [web] پیکربندی لایه
    @Autowired
    private ApplicationContext context;

    @Bean
    public DispatcherServlet dispatcherServlet() {
        DispatcherServlet servlet = new DispatcherServlet((WebApplicationContext) context);
        return servlet;
    }

    @Bean
    public ServletRegistrationBean servletRegistrationBean(DispatcherServlet dispatcherServlet) {
        return new ServletRegistrationBean(dispatcherServlet, "/*");
    }

    @Bean
    public EmbeddedServletContainerFactory embeddedServletContainerFactory() {
        return new TomcatEmbeddedServletContainerFactory("", 8081);
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/*.html").addResourceLocations("classpath:/static/");
        registry.addResourceHandler("/*.js").addResourceLocations("classpath:/static/js/");
    }
}
  • خط ۱۵: کلاس پروژه اسپرینگ MVC را پیکربندی می‌کند؛
  • خط 16: این کلاس از کلاس [WebMvcConfigurerAdapter] ارث می‌برد تا برخی از متدهای آن را بازنویسی کند؛
  • خطوط ۱۸–۳۶: ما قبلاً با این بین‌ها (beans) مواجه شده‌ایم، برای مثال در بخش ۱۳.۵.۳.۱. توجه کنید که در خط ۳۵، سرویس وب (web service) بر روی پورت ۸۰۸۱ اجرا خواهد شد؛
  • خطوط ۳۸–۴۲: متد [addResourceHandlers] اجازه می‌دهد منابع ایستا تعریف شوند، یعنی منابعی که توسط متد [DispatcherServlet] در خط ۲۳ پردازش نمی‌شوند؛
  • خط ۴۰: هر درخواستی برای یک منبع با پسوند .html، فایل مورد درخواست را که در پوشه [static] در مسیر کلاس پروژه یافت می‌شود، بازمی‌گرداند؛
  • خط ۴۱: هر درخواست برای منبعی با پسوند .js، فایل جاوااسکریپت مورد درخواست را که در پوشه [static/js] در مسیر کلاس‌پث پروژه قرار دارد، بازمی‌گرداند؛
  

18.5. مبانی jQuery و جاوااسکریپت

صفحه HTML مشتری به شرح زیر خواهد بود:

 

این شامل کد جاوااسکریپت (jS) خواهد بود که در مرورگر اجرا می‌شود. ما برخی از مبانی جاوااسکریپت را که به درک کد کمک می‌کنند، تشریح خواهیم کرد. کلاینت با استفاده از کتابخانه jQuery [https://jquery.com/] که توابع متعددی برای تسهیل توسعه جاوااسکریپت فراهم می‌کند، به HTTP فراخوانی خواهد کرد. ما یک فایل استاتیک HTML [jQuery.html] ایجاد می‌کنیم که آن را در پوشه [static] قرار می‌دهیم:

 

این فایل شامل موارد زیر خواهد بود:


<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>JQuery-01</title>
<script type="text/javascript" src="/jquery-2.1.3.min.js"></script>
</head>
<body>
    <h3>Rudiments de JQuery</h3>
    <div id="element1">Elément 1</div>
</body>
</html>
  • خط ۶: وارد کردن jQuery;
  • خطوط ۱۰–۱۲: یک عنصر از صفحه با شناسه [element1]. ما قصد داریم با این عنصر آزمایش کنیم.

ما باید فایل [jquery-2.1.3.min.js] را دانلود کنیم. آخرین نسخه jQuery را می‌توان در URL و [http://jquery.com/download/] پیدا کرد:

Image

فایل دانلود شده را در پوشه [static / js] قرار دهید و خط ۶ فایل HTML را مطابق با نسخه نصب‌شده اصلاح کنید.

پس از انجام این کار، با استفاده از Chrome [1-2] نمای ایستا [jQuery.html] را درخواست کنید:

در گوگل کروم، دستور [Ctrl-Maj-I] را اجرا کنید تا ابزارهای توسعه‌دهنده [3] باز شود. زبانه [Console] [4] به شما امکان می‌دهد کد جاوااسکریپت را اجرا کنید. در زیر، چند دستور جاوااسکریپت برای تایپ کردن همراه با توضیح هر یک ارائه شده است.

JS
résultat
$("#element1")
: مجموعه تمام عناصری را که دارای شناسه [element1] هستند، بازمی‌گرداند،
بنابراین معمولاً مجموعه‌ای با ۰ یا ۱ عنصر است
زیرا شما نمی‌توانید دو شناسه یکسان در یک صفحه واحد HTML داشته باشید.
$("#element1").text("blabla")
: متن [blabla] را به همه عناصر اعمال می‌کند
در این مجموعه. این تغییر می‌دهد
محتوای نمایش‌داده‌شده توسط صفحه را تغییر می‌دهد.
$("#element1").hide()
موارد موجود در مجموعه را پنهان می‌کند.
متن [blabla] دیگر نمایش داده نمی‌شود.
$("#element1")
: مجموعه را دوباره نمایش می‌دهد. این
به ما امکان می‌دهد ببینیم که عنصری با شناسه [element1] دارد
ویژگی CSS style='display: none;', که
باعث پنهان شدن عنصر می‌شود.
$("#element1").show()
: عناصر را در مجموعه نمایش می‌دهد. متن
متن '[blabla]' دوباره ظاهر می‌شود. این ویژگی است
CSS style='display: block;' که این را تضمین می‌کند
display.
$("#element1").attr('style','color: red')
: یک ویژگی را برای همه عناصر در ... تنظیم می‌کند
مجموعه. ویژگی در اینجا [style] است و مقدار آن
[color: red]. متن [blabla] به رنگ قرمز درمی‌آید.
Tableau
Dictionnaire

توجه کنید که URL مرورگر در طول این عملیات‌ها تغییر نکرده است. هیچ ارتباطی با سرور وب برقرار نشده است. همه چیز در داخل مرورگر اتفاق می‌افتد. اکنون، بیایید کد منبع صفحه را مشاهده کنیم:

این متن اصلی است. این متن تغییرات اعمال‌شده توسط ما بر عنصر در خطوط ۱۰ تا ۱۲ را منعکس نمی‌کند. هنگام اشکال‌زدایی جاوااسکریپت، مهم است که این موضوع را در نظر داشته باشید. بنابراین، مشاهده کد منبع صفحه نمایش‌داده‌شده اغلب بی‌فایده است.

18.6. کد جاوااسکریپت برنامه

بیایید به صفحهٔ برنامهٔ کلاینت بازگردیم که از سرویس وب / jSON پرس‌وجو خواهد کرد:

  
 

کد HTML برای این صفحه به شرح زیر است:


<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Spring MVC</title>
<script type="text/javascript" src="/jquery-2.1.3.min.js"></script>
<script type="text/javascript" src="/client.js"></script>
</head>
<body>
    <h2>Client du service web / jSON</h2>
    <form id="formulaire">
        <!-- نام کاربری -->
        Identifiant :
        <!--  -->
        <input type="text" id="identifiant" name="identifiant" value="" />
        <!--  رمز عبور -->
        <br /> <br /> Mot de passe :
        <!--  -->
        <input type="text" id="password" name="password" value="" />
        <!--  روش HTTP -->
        <br /> <br /> Méthode HTTP :
        <!--  -->
        <input type="radio" id="get" name="method" value="get"
            checked="checked" />GET
        <!--  -->
        <input type="radio" id="post" name="method" value="post" />POST
        <!--  URL -->
        <br /> <br />URL cible (commençant par /): <input type="text"
            id="url" size="30"><br />
        <!-- ارزش ارسال‌شده -->
        <br /> Chaîne jSON à poster : <input type="text" id="posted"
            size="50" />
        <!-- دکمه ارسال -->
        <br /> <br /> <input type="button" value="Valider"
            onclick="javascript:requestServer()"></input>
    </form>
    <hr />
    <h2>Réponse du serveur</h2>
    <div id="response"></div>
</body>
</html>
  • خط ۶: ما کتابخانه jQuery را وارد می‌کنیم؛
  • خط ۷: ما کدی را وارد می‌کنیم که قرار است بنویسیم؛
  • خطوط ۱۵، ۱۹، ۲۶، ۲۹، ۳۱: به شناسه‌های [id] برای اجزای صفحه توجه کنید. جاوااسکریپت از طریق این شناسه‌ها به این اجزا ارجاع می‌دهد؛

کد [client.js] به شرح زیر است:


// داده‌های جهانی
var url;
var posted;
var response;
var method;
var baseUrl = 'http://localhost:8080';
var identifiant;
var password;
var authorizationHeader;

function requestServer() {
    // بازیابی اطلاعات
    var urlValue = url.val();
    var postedValue = posted.val();
    var identifiantValue = identifiant.val();
    var passwordValue = password.val();
    var method = document.forms[0].elements['method'].value;
    authorizationCode = btoa(identifiantValue + ':' + passwordValue);
    // پاک کردن پاسخ قبلی
    response.text("");
    // انجام فراخوانی Ajax به‌صورت دستی
    if (method === "get") {
        doGet(urlValue);
    } else {
        doPost(urlValue, postedValue);
    }
}

function doGet(url) {
    // انجام یک فراخوانی دستی Ajax
    $.ajax({
        headers : {
            'احراز هویت: 'Basic ' + authorizationCode
        },
        url : baseUrl + url,
        type : 'GET',
        dataType : 'text',
        beforeSend : function() {
        },
        success : function(data) {
            // متن نتیجه
            response.text(data);
        },
        complete : function() {
        },
        error : function(jqXHR) {
            // خطای سیستم
            response.text(JSON.stringify(jqXHR.statusCode()));
        }
    })
}

function doPost(url, posted) {
    // یک فراخوانی Ajax به‌صورت دستی انجام می‌شود
    $.ajax({
        headers : {
            'Authorisation':'Basic '+authorizationCode
        },
        url : baseUrl + url,
        type : 'POST',
        contentType : 'application/json; charset=UTF-8',
        data : posted,
        dataType : 'text',
        beforeSend : function() {
        },
        success : function(data) {
            // نتیجه متنی
            response.text(data);
        },
        complete : function() {
        },
        error : function(jqXHR) {
            // خطای سیستم
            response.text(JSON.stringify(jqXHR.statusCode()));
        }
    })
}

// هنگام بارگذاری سند
$(document).ready(function() {
    //ارجاعات اجزای صفحه را بازیابی می‌کند
    identifiant = $("#identifiant");
    password = $("#password");
    url = $("#url");
    posted = $("#posted");
    response = $("#response");
});
  • خطوط ۸۰–۸۷: بخشی از کد jS که پس از اتمام بارگذاری سند در مرورگر اجرا می‌شود؛
  • خطوط ۸۱–۸۶: ارجاعات به عناصر مختلف سند HTML از طریق شناسه‌های [id] آنها بازیابی می‌شوند؛
  • خطوط ۲–۹: متغیرهای سراسری که از تمام توابع تعریف‌شده در فایل jS قابل دسترسی هستند؛
  • خط ۱۳: مقدار واردشده توسط کاربر از URL بازیابی می‌شود؛
  • خط ۱۴: مقداری که کاربر می‌خواهد ارسال کند بازیابی می‌شود (خالی اگر عملیات GET باشد);
  • خط ۱۵: بازیابی نام کاربری وارد شده توسط کاربر؛
  • خط ۱۶: بازیابی رمز عبور آنها؛
  • خط ۱۷: متدی را که باید برای درخواست URL از خط ۹ استفاده شود، بازیابی می‌کنیم: [get] یا [post
    • [document] به سندی اشاره دارد که توسط مرورگر بارگذاری شده و به عنوان DOM (مدل شیء سند) شناخته می‌شود،
    • [document.forms[0].elements['method']] به اولین فرم در سند اشاره دارد؛ یک سند ممکن است حاوی چندین فرم باشد. در این مورد، تنها یک فرم وجود دارد،
    • [document.forms[0].elements['method']] به عنصر فرم اشاره دارد که دارای صفت [name='method'] است. دو مورد از آنها وجود دارد:

<input type="radio" id="get" name="method" value="get" checked="checked" />GET
<input type="radio" id="post" name="method" value="post" />POST
  • (ادامه)
    • [document.forms[0].elements['method'].value] مقداری است که برای کامپوننت با ویژگی [name='method'] ارسال خواهد شد. ما می‌دانیم که مقدار ارسال‌شده، مقدار ویژگی [value] دکمه رادیویی انتخاب‌شده است. بنابراین، در اینجا این مقدار یکی از رشته‌های ['get', 'post'] خواهد بود؛
  • خط ۱۸: ما رمزگذاری Base74 رشته 'username:password' را انجام می‌دهیم. این رشته رمزگذاری‌شده در هدر 'HTTP [Authorization]' که برای احراز هویت درخواست به سرور ارسال می‌کنیم، استفاده خواهد شد؛
  • خطوط ۲۲–۲۶: بسته به اینکه کدام روش (HTTP) قرار است استفاده شود، ما روش [doGet] یا [doPost] را اجرا می‌کنیم؛
  • روش jQuery [$.ajax] فراخوانی‌ای به HTTP انجام می‌دهد؛
  • خطوط ۳۲–۳۴: درخواستی به سروری ارسال می‌شود که نیازمند هدر از نوع HTTP یا [Authorization: Basic code] است؛
  • خط ۳۵: کاربر مقدار URL از نوع [/cors-getAllCategories,/cors-addProduits, ...] را وارد خواهد کرد. بنابراین این URL باید با URL سرور از خط ۶ تکمیل شود؛
  • خط ۳۶: باید از متد HTTP استفاده شود؛
  • خط ۳۷: سرور jSON را بازمی‌گرداند. نوع [text] به‌عنوان نوع نتیجه مشخص شده است تا دقیقاً همان‌طور که دریافت شده نمایش داده شود؛
  • خط ۴۲: نمایش پاسخ متنی سرور؛
  • خطوط ۴۸–۴۹: نمایش هرگونه پیام خطا؛
  • خط ۵۳: متد [doPost] یک پارامتر دوم می‌گیرد که مقداری است که باید ارسال شود؛
  • خط ۶۱: برای نشان دادن اینکه مقداری که باید ارسال شود به شکل یک رشته jSON خواهد بود؛

18.7. اجرای کلاینت

برنامهٔ کلاینت یک برنامهٔ Spring Boot است که توسط کلاس اجرایی زیر، [Boot]، راه‌اندازی می‌شود:

  

package spring.cors.client.boot;

import org.springframework.boot.SpringApplication;

import spring.cors.client.config.WebConfig;

public class Boot {

    public static void main(String[] args) {
        SpringApplication.run(WebConfig.class, args);
    }
}
  • خط ۱۰: متد [SpringApplication.run] از فایل پیکربندی [WebConfig] استفاده می‌کند. صفحه [client.html] روی سرور Tomcat موجود در classpath پروژه مستقر خواهد شد؛

18.8. URL [/getAllCategories]

ما در حال راه‌اندازی هستیم:

  • سرور وب/JSON روی پورت 8080؛
  • کلاینت این سرور بر روی پورت 8081؛

سپس URL [http://localhost:8081/client.html] [1] را درخواست می‌کنیم:

  • به [2]، یک GET را روی URL [http://localhost:8080/getAllCategories] انجام می‌دهیم؛

ما پاسخی از سرور دریافت نمی‌کنیم. وقتی به کنسول توسعه‌دهنده کروم (Ctrl+Shift+I) نگاه می‌کنیم، با خطایی مواجه می‌شویم:

  • در [1]، ما روی زبانه [Network] هستیم؛
  • در [2]، می‌توانیم ببینیم که درخواست HTTP که ارسال شده، [GET] نیست، بلکه [OPTIONS] است. در مورد درخواست بین‌دامنه‌ای، مرورگر با ارسال درخواستی به سرور HTTP [OPTIONS] بررسی می‌کند که تعدادی از شرایط برآورده شده است. در این مورد، درخواست‌ها همان‌هایی هستند که با نقاط [5-6] نشان داده شده‌اند؛
  • در [5]، مرورگر می‌پرسد که آیا هدف URL از طریق یک GET قابل دسترسی است یا خیر. سربرگ درخواست [Access-Control-Request-Method]، پاسخی را با سربرگ HTTP [Access-Control-Allow-Methods] درخواست می‌کند که نشان دهد روش درخواستی پذیرفته شده است؛
  • در [6]، مرورگر هدر HTTP [Origin: http://localhost:8081] را ارسال می‌کند. این هدر درخواست پاسخی را در یک هدر HTTP [Access-Control-Allow-Origin] ارسال می‌کند که نشان می‌دهد منشأ مشخص‌شده پذیرفته شده است؛
  • در [7]، مرورگر می‌پرسد که آیا سربرگ‌های HTTP، [accept] و [authorization] پذیرفته می‌شوند یا خیر. سربرگ درخواست [Access-Control-Request-Headers] منتظر پاسخی با سربرگ HTTP [Access-Control-Allow-Headers] است که نشان دهد سربرگ‌های درخواستی پذیرفته شده‌اند؛
  • در [3] خطایی رخ می‌دهد. کلیک بر روی آیکون منجر به خطای [4] می‌شود؛
  • در [4]، پیام نشان می‌دهد که سرور هدر HTTP [Access-Control-Allow-Origin] را که مشخص می‌کند آیا منشأ درخواست پذیرفته شده است یا خیر، ارسال نکرده است؛
  • در [8]، می‌توانیم ببینیم که سرور واقعاً این هدر را ارسال نکرده است. در نتیجه، مرورگر از انجام درخواست HTTP GET که در ابتدا درخواست شده بود، خودداری کرده است؛

ما باید وب‌سرور / jSON را اصلاح کنیم.

18.9. سرویس وب جدید / json

ما یک پروژه جدید Maven به نام [intro-spring-cors-server-jpa] ایجاد می‌کنیم:

18.9.1. پیکربندی Maven

پیکربندی Maven برای سرویس وب جدید به شرح زیر است:


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>istia.st.cors</groupId>
    <artifactId>spring-cors-server-jpa</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <name>spring-cors-server-jpa</name>
    <description>démo spring cors</description>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.7.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>istia.st.spring.security</groupId>
            <artifactId>intro-spring-security-server-01</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies>

    <!--افزونه‌ها -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.18.1</version>
            </plugin>
        </plugins>
    </build>

</project>
  • خطوط ۲۳–۲۷: ما تمام کارهای انجام‌شده تا به اینجا را با استفاده از وب‌سرور امن / آرشیو json ادغام می‌کنیم؛

18.9.2. پیکربندی Spring

کلاس پیکربندی [AppConfig] به شرح زیر است:

  

package spring.cors.server.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

import spring.security.config.SecurityConfig;

@Configuration
@ComponentScan(basePackages = { "spring.cors.server.service" })
@Import({ SecurityConfig.class })
public class AppConfig {

    // درخواست‌های بین‌دامنه‌ای
    @Bean
    public boolean isCorsEnabled() {
        return true;
    }
}
  • خط ۱۰: این کلاس یک کلاس پیکربندی Spring است؛
  • خط ۱۱: سایر کامپوننت‌های Spring در پکیج [spring.cors.server.service] قرار دارند؛
  • خطوط 16–19: ما یک کامپوننت اسپرینگ به نام [isCorsEnabled] ایجاد می‌کنیم که مشخص می‌کند آیا باید کلاینت‌ها را از خارج دامنه سرور بپذیریم یا خیر؛

18.9.3. کلاس [AbstractCorsController]

کلاس [AbstractCorsController] که کلاس والد برای همه کنترل‌کننده‌ها در این برنامه خواهد بود:

 

کد آن به شرح زیر است:


package spring.cors.server.service;

import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;

public abstract class AbstractCorsController {

    @Autowired
    private boolean isCorsEnabled;

    //ارسال گزینه‌ها به کلاینت
    public void setHeaders(String origin, HttpServletResponse response) {
        //آیا CORS مجاز است؟
        if (!isCorsEnabled || origin == null || !origin.startsWith("http://localhost")) {
            return;
        }
        // سربرگ CORS را تنظیم کنید
        response.addHeader("Access-Control-Allow-Origin", origin);
        // سرور برخی هدرها را مجاز می‌داند
        response.addHeader("Access-Control-Allow-Headers", "accept, authorization");
        // GET مجاز است
        response.addHeader("Access-Control-Allow-Methods", "GET");
    }
}
  • خط ۷: کلاس [CorsController] انتزاعی است زیرا برای گسترش طراحی شده و نه برای نمونه‌سازی؛
  • خطوط ۱۳–۲۴: متد [setHeaders] سربرگ‌های HTTP را که برای درخواست‌های بین‌دامنه‌ای الزامی هستند، در پاسخ [HttpServletResponse response] (خط ۱۳) که به کلاینت ارسال می‌شود، درج می‌کند؛
  • خط ۳۳: متد [/setHeaders] پارامترهای زیر را می‌پذیرد:
    • رشته [origin] که در سربرگ‌های HTTP و [Origin] درخواست‌های بین‌دامنه‌ای وجود دارد:
Origin:http://localhost:8081

در اینجا، پارامتر [origin] در خط ۱۳ دارای مقدار [http://localhost:8081] خواهد بود. اگر درخواست حاوی هدر HTTP [Origin] نباشد، ما اطمینان حاصل می‌کنیم که از [origin==null] استفاده شود؛

  • (ادامه)
    • شیء [HttpServletResponse response]، که به کلاینتی که درخواست را ارسال کرده بازگردانده خواهد شد؛

این دو پارامتر توسط Spring تزریق می‌شوند؛

  • خطوط ۱۵–۱۷۵: اگر برنامه برای پذیرش درخواست‌های بین‌دامنه‌ای پیکربندی شده باشد، و اگر فرستنده هدر HTTP [Origin] را ارسال کرده باشد، و اگر این مبدا با [http://localhost] شروع شود، در این صورت درخواست بین‌دامنه‌ای پذیرفته می‌شود؛ در غیر این صورت، رد خواهد شد؛
  • خط ۱۹: اگر کلاینت در دامنه [http://localhost:port] باشد، هدر HTTP ارسال می‌شود:
Access-Control-Allow-Origin:  http://localhost:port

که به این معنی است که سرور منشأ کلاینت را می‌پذیرد؛

  • خط ۲۱: ما دو هدر خاص HTTP را در درخواست HTTP [OPTIONS] شناسایی کرده‌ایم:
Access-Control-Request-Method: GET
Access-Control-Request-Headers: accept, authorization

در پاسخ به سربرگ‌های HTTP و [Access-Control-Request-X]، سرور با سربرگ‌های HTTP و [Access-Control-Allow-X] پاسخ می‌دهد که در آن‌ها مشخص می‌کند چه چیزی مجاز است. خطوط ۲۰ تا ۲۳ صرفاً درخواست کلاینت را تکرار می‌کنند تا نشان دهند که پذیرفته شده است؛

18.9.4. کنترل‌کننده [MyControllerWithHttpOptions]

برای جلوگیری از نیاز به اصلاح وب‌سرور ناامن / jSON [intro-server-webjson-01] که در بخش 13.5.3 مورد بحث قرار گرفته است، ما یک کنترل‌کننده جدید ایجاد خواهیم کرد تا در مواردی که سرور ناامن، URL و [/url] را پردازش می‌کند، کنترل‌کننده جدید، URL و [/cors-url] را مدیریت خواهد کرد و این URL درخواست‌های بین‌دامنه‌ای را می‌پذیرد.

کلاس [MyControllerWithHttpOptions] کنترلگری است که درخواست‌های HTTP از نوع [OPTIONS] را پردازش می‌کند:

 

package spring.cors.server.service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.fasterxml.jackson.core.JsonProcessingException;

@Controller
public class MyControllerWithHttpOptions extends AbstractCorsController {

    @RequestMapping(value = "/cors-getAllCategories", method = RequestMethod.OPTIONS)
    public void getAllCategories(@RequestHeader(value = "Origin", required = false) String origin,
            HttpServletResponse httpServletResponse){
        // سربرگ‌ها CORS
        setHeaders(origin, httpServletResponse);
    }
...
  • خط ۱۴: این کلاس یک کنترل‌کننده Spring MVC است؛
  • خط ۱۵: کلاس [MyControllerWithHttpOptions] از کلاس [AbstractCorsController] که همین‌اکنون توصیف کردیم، ارث می‌برد؛
  • خطوط 17–18: متد [getAllCategories] (خط ۱۸) متد URL و ["/cors-getAllCategories"] را زمانی که از طریق متد HTTP و [OPTIONS] فراخوانی می‌شوند، پردازش می‌کند؛
  • خط ۱۸: متد [getAllCategories] دو پارامتر را می‌پذیرد:
    • [@RequestHeader(value = "Origin", required = false) String origin] برای بازیابی مقدار هدر HTTP [Origin:http://localhost:8081] در صورت وجود. در این مثال، پارامتر [String origin] مقدار [http://localhost:8081] را خواهد داشت. این هدر اجباری نیست ([required = false]). اگر این هدر وجود نداشته باشد، پارامتر [String origin] مقدار null را خواهد داشت؛
    • [HttpServletResponse httpServletResponse]: پاسخی که باید به کلاینت ارسال شود؛
  • خط ۲۱: سربرگ‌های HTTP ارسال می‌شوند که درخواست‌های بین‌دامنه‌ای را فعال می‌کنند. متد [setHeaders] در کلاس والد [AbstractCorsController] تعریف شده است؛

این موضوع در مورد تمام متدهای URL که توسط وب‌سرور / jSON ([intro-server-webjson-01] ناامن مورد بحث در بخش 13.5.3) ارائه می‌شوند، صدق می‌کند. هنگامی که این سرویس، URL و [/url] را در معرض دید قرار می‌دهد، کلاس [MyControllerWithHttpOptions] که در بالا ذکر شد، URL و [/cors-url] را در معرض دید قرار می‌دهد.

18.9.5. کنترل‌کننده [MyControllerWithCors]

 

کلاس [MyControllerWithCors] کنترلگری است که درخواست‌های از نوع HTTP، مانند [GET] و [POST] را مدیریت می‌کند:


package spring.cors.server.service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.fasterxml.jackson.core.JsonProcessingException;

import spring.webjson.service.MyController;

@Controller
public class MyControllerWithCors extends AbstractCorsController {

    //وابستگی‌های Spring
    @Autowired
    private MyController myController;

...
    @RequestMapping(value = "/cors-getAllCategories", method = RequestMethod.GET, produces = "application/json; charset=UTF-8")
    @ResponseBody
    public String getAllCategories(@RequestHeader(value = "Origin", required = false) String origin,
            HttpServletResponse httpServletResponse) throws JsonProcessingException {
        // پاسخ
        return myController.getAllCategories();
    }
...
  • خط 17: کلاس [MyControllerWithCors] یک کنترلر Spring MVC است
  • خط ۱۸: این کلاس را از کلاس [AbstractCorsController] ارث می‌برد؛
  • خطوط ۲۱–۲۲: تزریق کنترل‌کننده [MyController] از سرور وب / jSON و [intro-server-webjson-01] ناامن که در بخش ۱۳.۵.۳ مورد بحث قرار گرفته‌اند؛
  • خطوط ۲۵–۲۷: متد [getAllCategories] پردازش‌های URL و [/cors-getAllCategories] را انجام می‌دهد (خط ۲۸) زمانی که از طریق متد HTTP [GET] درخواست شود؛
  • خط ۲۶: نتیجه روش [getAllCategories] به کلاینت ارسال خواهد شد. این نتیجه یک استریم jSON است (ویژگی [produces] در خط ۲۷ و نوع نتیجه [String] در خط ۲۵)؛
  • خط ۲۷: این متد همان پارامترهای متد [getAllCategories] از کنترلر [MyControllerWithHttpOptions] را که به تازگی بررسی کردیم، دریافت می‌کند؛
  • خط ۳۰: به متد [myController.getAllCategories()] دستور داده می‌شود که پاسخ را ارسال کند؛

در نهایت، این متد [myController.getAllCategories()] در سرور ناامن است که پاسخ را ارسال می‌کند. ما به سادگی پاسخ آن را با سربرگ‌های مورد نیاز برای درخواست‌های بین‌دامنه‌ای غنی‌سازی کرده‌ایم.

این کار برای تمام متدهای URL که توسط وب‌سرور / jSON – [intro-server-webjson-01] ناامن که در بخش 13.5.3 مورد بحث قرار گرفته است – ارائه شده‌اند، انجام می‌شود. هنگامی که این سرویس، کلاس‌های URL و [/url] را در معرض دید قرار می‌دهد، کلاس [MyControllerWithCors] که در بالا ذکر شد، کلاس‌های URL و [/cors-url] را در معرض دید قرار می‌دهد.

یک درخواست بین‌دامنه‌ای به شرح زیر انجام می‌شود:

  • کد کلاینت JS درخواست می‌کندURL و [/cors-url] با استفاده از درخواستی برای HTTP، GET یا POST فراخوانی می‌شوند؛
  • مرورگری که این کد را اجرا می‌کند این درخواست را رهگیری کرده و ابتدا درخواست می‌کندURL [/cors-url] با درخواستی HTTP OPTIONS برای تأیید اینکه سرویس وب هدف درخواست‌های بین‌دامنه‌ای را می‌پذیرد؛
  • یکی از متدهای کنترل‌کننده [MyControllerWithHttpOptions] سربرگ‌های فرا-دامین مورد انتظار مرورگر را ارسال می‌کند؛
  • سپس مرورگر درخواست اولیه URL ([/cors-url]) را با درخواستی برای HTTP، GET یا POST ارسال می‌کند؛
  • سپس یکی از متدهای کنترل‌کننده [MyControllerWithCors] پاسخ می‌دهد؛

18.9.6. آزمایش‌ها

کلاس بوت برای پروژه [intro-spring-cors-server-jpa] به شرح زیر است:

  

package spring.cors.server.boot;

import org.springframework.boot.SpringApplication;

import spring.cors.server.config.AppConfig;

public class Boot {

    public static void main(String[] args) {
        SpringApplication.run(AppConfig.class, args);
    }
}
  • خط ۱۰: متد استاتیک [SpringApplication.run] با پیکربندی Spring [AppConfig] اجرا می‌شود. در نتیجه این پیکربندی، سرور Tomcat تعبیه‌شده در آرشیوهای پروژه راه‌اندازی شده و اپلیکیشن وب [intro-spring-cors-server-jpa] روی آن مستقر می‌شود. برنامه وب برای سرور ناامن [intro-server-webjson-01] که بخشی از آرشیوهای پروژه است نیز روی آن مستقر می‌شود. از آنجا که پروژه [intro-spring-security-server-01] نیز بخشی از آرشیوها است، در نهایت دو نوع URL نمایان می‌شوند:
    • آن‌هایی که مربوط به سرویس وب امن هستند: /url;
    • آن‌هایی که سرویس وب پذیرش درخواست‌های بین‌دامنه‌ای را بر عهده دارد: /cors-url;

اکنون برای آزمایش‌های بیشتر آماده‌ایم. ما نسخه جدید سرویس وب را راه‌اندازی می‌کنیم و متوجه می‌شویم که مشکل همچنان حل نشده باقی مانده است. هیچ چیز تغییر نکرده است. اگر یک خروجی کنسول در خط ۷ زیر اضافه کنیم، هرگز نمایش داده نمی‌شود، که این نشان می‌دهد متد [getAllCategories] از کلاس [MyControllerWithHttpOptions] هرگز فراخوانی نمی‌شود؛


@Controller
public class MyControllerWithHttpOptions extends AbstractCorsController {

    @RequestMapping(value = "/cors-getAllCategories", method = RequestMethod.OPTIONS)
    public void getAllCategories(@RequestHeader(value = "Origin", required = false) String origin,
            HttpServletResponse httpServletResponse){
        System.out.println(un_texte) ;
        // سربرگ‌ها CORS
        setHeaders(origin, httpServletResponse);
    }

پس از انجام تحقیقات، متوجه می‌شویم که به طور پیش‌فرض، Spring MVC خود دستورات HTTP و [OPTIONS] را مدیریت می‌کند. بنابراین همیشه Spring پاسخ می‌دهد و هرگز متد [getAllCategories] در خط ۵ بالا نیست. این رفتار پیش‌فرض Spring MVC قابل تغییر است. ما کلاس موجود [AppConfig] را اصلاح می‌کنیم:

  

package spring.cors.server.config;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.servlet.DispatcherServlet;

import spring.security.config.SecurityConfig;

@Configuration
@ComponentScan(basePackages = { "spring.cors.server.service" })
@Import({ SecurityConfig.class })
public class AppConfig {

    // درخواست‌های بین‌دامنه‌ای
    @Bean
    public boolean isCorsEnabled() {
        return true;
    }

    @Autowired
    private DispatcherServlet dispatcherServlet;

    @PostConstruct
    public void init() {
        // برنامه درخواست‌ها را خود پردازش می‌کند HTTP [OPTIONS]
        dispatcherServlet.setDispatchOptionsRequest(true);
    }
}
  • خطوط ۲۵–۲۶: تزریق بیون [dispatcherServlet] که درخواست‌های کلاینت را مدیریت می‌کند. این بیون در پیکربندی سرور وب / jSON (غیرمحافظت‌شده) [intro-server-webjson-01] که در بخش ۱۳.۵.۳ مورد بحث قرار گرفته است، تعریف شده است؛
  • خطوط ۲۸–۲۹: متد [init] (خط ۲۹) به محض اینکه کلاس [AppConfig] نمونه سازی شده و تزریق‌های Spring انجام شده باشد، اجرا خواهد شد. بنابراین، زمانی که این متد اجرا می‌شود، فیلد موجود در خط ۲۶ قبلاً مقداردهی اولیه شده است؛
  • خط ۳۱: ما بیان [dispatcherServlet] را طوری پیکربندی می‌کنیم که به برنامه وب اجازه دهد تا دستورات HTTP و [OPTIONS] را خود مدیریت کند؛

ما تست‌ها را با این پیکربندی جدید دوباره اجرا می‌کنیم. نتیجه زیر را به دست می‌آوریم:

  • در [1]، می‌توانیم ببینیم که دو درخواست، HTTP، به URL و [http://localhost:8080/cors-getAllCategories] وجود دارد؛
  • در [2]، درخواست [OPTIONS
  • در [3]، سه هدر HTTP که ما همین‌اکنون در پاسخ سرور پیکربندی کرده‌ایم؛

اکنون درخواست دوم را بررسی کنیم:

  • به [1]، درخواستی که در حال بررسی است؛
  • به [2]، که همان درخواست GET است. به لطف درخواست اول، [OPTIONS]، مرورگر اطلاعاتی را که درخواست کرده بود دریافت کرد. اکنون در حال اجرای درخواست [GET] است که در ابتدا درخواست شده بود؛
  • در [3]، پاسخ سرور؛
  • در [4]، سرور jSON را ارسال می‌کند؛
  • در [5]، خطایی رخ داده است؛
  • در [6]، پیام خطا؛

توضیح آنچه در اینجا رخ داده دشوارتر است. پاسخ سرور [3] طبیعی است ([HTTP/1.1 200 OK]). بنابراین ما باید سند درخواستی را داشته باشیم. ممکن است سرور واقعاً سند را ارسال کرده باشد اما مرورگر از استفاده از آن جلوگیری می‌کند زیرا نیاز دارد که پاسخ به درخواست GET همچنین شامل هدر HTTP [Access-Control-Allow-Origin:http://localhost:8081] باشد.

بنابراین، کنترل‌کننده [MyControllerWithCors] را اصلاح می‌کنیم تا آن نیز سربرگ‌های لازم برای درخواست‌های بین‌دامنه‌ای را ارسال کند:


    @RequestMapping(value = "/cors-getAllCategories", method = RequestMethod.GET, produces = "application/json; charset=UTF-8")
    @ResponseBody
    public String getAllCategories(@RequestHeader(value = "Origin", required = false) String origin,
            HttpServletResponse httpServletResponse) throws JsonProcessingException {
        // سربرگ‌ها CORS
        setHeaders(origin, httpServletResponse);
        // پاسخ
        return myController.getAllCategories();
}
  • خط ۶: سربرگ‌های مورد نیاز برای درخواست‌های بین‌دامنه‌ای در پاسخ گنجانده شده‌اند؛

پس از این تغییر، نتایج به شرح زیر است:

ما در واقع فهرست دسته‌بندی‌ها را به دست آوردیم.

18.10. سایر: URL, [GET]

در کنترل‌کننده‌های [MyControllerWithCors, MyControllerWithHttpOptions]، کد مربوط به اقداماتی که درخواست‌های URL را با استفاده از [GET] مدیریت می‌کنند، از الگوی اقداماتی پیروی می‌کند که قبلاً درخواست‌های URL و [/cors-getAllCategories] را مدیریت می‌کردند. خوانندگان می‌توانند کد را در مثال‌های ارائه‌شده همراه این سند بررسی کنند. در اینجا مثالی برای URL و [/cors-getAllProduits] آورده شده است:

در [MyControllerWithHttpOptions]


    @RequestMapping(value = "/cors-getAllProduits", method = RequestMethod.OPTIONS)
    public void getAllProduits(@RequestHeader(value = "Origin", required = false) String origin,
            HttpServletResponse httpServletResponse) {
        // سربرگ‌ها CORS
        setHeaders(origin, httpServletResponse);
}

در [MyControllerWithCors]


    @RequestMapping(value = "/cors-getAllProduits", method = RequestMethod.GET, produces = "application/json; charset=UTF-8")
    @ResponseBody
    public String getAllProduits(@RequestHeader(value = "Origin", required = false) String origin,
            HttpServletResponse httpServletResponse) throws JsonProcessingException {
        // سربرگ‌ها CORS
        setHeaders(origin, httpServletResponse);
        // پاسخ
        return myController.getAllProduits();
}

نتیجهٔ به‌دست‌آمده به شرح زیر است:

18.11. URL [POST]

بیایید مورد زیر را بررسی کنیم:

  • ما یک POST [1] را به URL [2] ایجاد می‌کنیم؛
  • در [3]، مقدار ارسال‌شده. این یک رشته jSON است؛
  • در مجموع، قصد داریم یک دسته‌بندی به نام [categorie2] ایجاد کنیم؛

در این مرحله هیچ کدی را تغییر نمی‌دهیم. نتیجهٔ به‌دست‌آمده به شرح زیر است:

  • در [1]، همانند درخواست‌های [GET]، درخواستی برای [OPTIONS] توسط مرورگر ارسال می‌شود؛
  • برای [2]، درخواست مجوز دسترسی برای درخواستی برای [POST] ارسال می‌شود. قبلاً این [GET] بود؛
  • در [3]، درخواست مجوز برای ارسال سربرگ‌های HTTP و [accept, authorization, content-type] می‌شود. قبلاً، فقط دو سربرگ اول موجود بودند؛
  • در [4]، سرویس وب همهٔ مجوزهای درخواستی را اعطا نمی‌کند، که باعث خطای [5] می‌شود؛

ما روش [AbstractController.sendHeaders] را به شرح زیر اصلاح می‌کنیم:


package spring.cors.server.service;

import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;

public abstract class AbstractCorsController {

    @Autowired
    private boolean isCorsEnabled;

    // گزینه‌های ارسال به کلاینت
    public void setHeaders(String origin, HttpServletResponse response) {
        // آیا CORS مجاز است؟
        if (!isCorsEnabled || origin == null || !origin.startsWith("http://localhost")) {
            return;
        }
        // سربرگ CORS را تنظیم کنید
        response.addHeader("Access-Control-Allow-Origin", origin);
        //برخی هدرها مجاز هستند
        response.addHeader("Access-Control-Allow-Headers", "accept, authorization, content-type");
        // GET و POST مجاز هستند
        response.addHeader("Access-Control-Allow-Methods", "GET, POST");
    }
}
  • خط ۲۱: ما هدر HTTP [Content-Type] را اضافه کرده‌ایم (حالت حروف مهم نیست);
  • خط ۲۳: متد HTTP [POST] اضافه شده است؛

این بدان معناست که متدهای [POST] به همان شیوه‌ای که درخواست‌های [GET] پردازش می‌شوند، مدیریت می‌گردند. در اینجا مثالی از URL [/cors-addArticles] آورده شده است:

در [MyControllerWithCors]


    @RequestMapping(value = "/cors-addCategories", method = RequestMethod.POST, consumes = "application/json; charset=UTF-8", produces = "application/json; charset=UTF-8")
    @ResponseBody
    public String addCategories(HttpServletRequest request,
            @RequestHeader(value = "Origin", required = false) String origin, HttpServletResponse httpServletResponse)
                    throws JsonProcessingException {
        // سربرگ‌های CORS
        setHeaders(origin, httpServletResponse);
        //پاسخ
        return myController.addCategories(request);
}

در [MyControllerWithHttpOptions]


    @RequestMapping(value = "/cors-addCategories", method = RequestMethod.OPTIONS)
    public void addCategories(HttpServletRequest request,
            @RequestHeader(value = "Origin", required = false) String origin, HttpServletResponse httpServletResponse)
                    throws JsonProcessingException {
        // سربرگ‌ها CORS
        setHeaders(origin, httpServletResponse);
}

نتیجهٔ به‌دست‌آمده به شرح زیر است:

 

کategori [categorie2] با موفقیت به پایگاه داده اضافه شد. SGBD کلید اصلی 1729 را به آن اختصاص داد.

18.12. کنترل‌کننده [AuthenticateCorsController]

  

کنترل‌کننده [AuthenticateCorsController] برای فراهم کردن ... وجود داردURL [/cors-authenticate]، که امکان فراخوانی موجود URL [/authenticate] را از طریق یک درخواست بین‌دامنه‌ای فراهم می‌کند. کد آن به شرح زیر است:


package spring.cors.server.service;

import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.fasterxml.jackson.core.JsonProcessingException;

import spring.security.service.AuthenticateController;

@Controller
public class AuthenticateCorsController extends AbstractCorsController {
    @Autowired
    private AuthenticateController authenticateController;

    @RequestMapping(value = "/cors-authenticate", method = RequestMethod.GET)
    @ResponseBody
    public String authenticate(@RequestHeader(value = "Origin", required = false) String origin,
            HttpServletResponse response) throws JsonProcessingException {
        // سربرگ‌ها CORS
        setHeaders(origin, response);
        // روش منبع
        return authenticateController.authenticate();
    }

    @RequestMapping(value = "/cors-authenticate", method = RequestMethod.OPTIONS)
    public void corsAuthenticate(@RequestHeader(value = "Origin", required = false) String origin,
            HttpServletResponse response) {
        // سربرگ‌ها CORS
        setHeaders(origin, response);
    }

}

در اینجا دو مثال آورده شده است:

  • پاسخ‌ها با استفاده از کد زیر نمایش داده می‌شوند: jS:

function doGet(url) {
    // یک فراخوانی Ajax به‌صورت دستی انجام می‌شود
    $.ajax({
        headers : {
            'احراز هویت: 'Basic ' + authorizationCode
        },
        url : baseUrl + url,
        type : 'GET',
        dataType : 'text',
        beforeSend : function() {
        },
        success : function(data) {
            // متن نتیجه
            response.text(data);
        },
        complete : function() {
        },
        error : function(jqXHR) {
            // خطای سیستم
            response.text(JSON.stringify(jqXHR.statusCode()));
        }
    })
}
  • پاسخ [1] توسط خط 14 از تابع [success] نمایش داده می‌شود؛
  • پاسخ [2] توسط خط ۲۰ تابع [error] نمایش داده می‌شود. تابع [JSON.stringify] رشته jSON را از شیء [jqXHR.statusCode()] ایجاد می‌کند که شیئی است که خطای رخ‌داده را در بر می‌گیرد. این شیء اطلاعات کمی ارائه می‌دهد. امکان استفاده از متدهای دیگر شیء [jqXHR] برای به دست آوردن، برای مثال، سربرگ‌های HTTP که توسط سرور بازگردانده می‌شوند، وجود دارد؛

18.13. Conclusion

اپلیکیشن ما اکنون از درخواست‌های بین‌دامنه‌ای پشتیبانی می‌کند. این درخواست‌ها را می‌توان از طریق پیکربندی در کلاس [AppConfig] فعال یا غیرفعال کرد:


@ComponentScan(basePackages = { "spring.cors.server.service" })
@Import({ SecurityConfig.class })
public class AppConfig {

    // درخواست‌های بین‌دامنه‌ای
    @Bean
    public boolean isCorsEnabled() {
        return true;
    }

    @Autowired
    private DispatcherServlet dispatcherServlet;

    @PostConstruct
    public void init() {
        // برنامه درخواست‌ها را خود مدیریت می‌کند HTTP [OPTIONS]
        dispatcherServlet.setDispatchOptionsRequest(true);
    }
}