Objective
Browser for security reasons, limited JS to launch a cross-station request, the use of XHR object to initiate a request must follow the homology policy (sop:same Origin Policy), the Cross-site request will be blocked by the browser, which is very painful for developers, especially to develop the front and back separation of the application.
In the modern web development, the resource data sharing is more and more common in different network environment, the homologous strategy can be said to restrict the development of the Web API to some extent.
Simply put, Cors is for Ajax to be secure across domains. As for the safety research of cors, this article does not discuss. Directory
A brief introduction to Cors
How to use. HTTP headers for Cors
Initial Project Preparation
Corsfilter: Cors of the filter stage
Corsinterceptor: Cors of the Interceptor phase
@CrossOrigin: The cors of Handler stage
Summary
The pursuit of the ultimate development experience: integration of Third-party Corsfilter
Sample code Download Cors a brief summary
Terminology interpretation: Cross-domain resource sharing (cross-origin Resource sharing)
Concept: is a cross-domain mechanism, norms, standards, how to call all the same, but this set of standards for the service side, and the browser side as long as the support HTML5 can.
Role: Can let the service side decide which request source can come in to take the data, so the service end plays the leading role (so out of the matter to find Backstage program ape, irrelevant front end ^ ^)
Common scenarios: full separation of the front and back end applications, such as hybrid App open read-only API,JS can access, such as maps, weather, time ... How to use. HTTP headers for Cors
To achieve cors Cross-domain is very simple, in the end, it is a series of HTTP headers in the server, mainly divided into the request headers and response headers, in the request and response to add these HTTP headers can easily achieve cors
The request header and the response header information are set at the server side, usually set in the filter phase, the browser end does not care, the only place to set is: whether to carry the cookie HTTP request header across the domain:
#请求域
Origin: "http://localhost:3000"
#这两个属性只出现在预检请求中, the options request
Access-control-request-method: "POST "
access-control-request-headers:" Content-type "
HTTP Response headers:
#允许向该服务器提交请求的URI, * means all allow, in Springmvc, if set to *, will automatically turn to the Origin Access-control-allow-origin in the current request header
: "http:// localhost:3000 "
#允许访问的头信息
access-control-expose-headers:" Set-cookie "
#预检请求的缓存时间 (seconds), that is, in this time period, The same Cross-domain request is not checked for
access-control-max-age: "1800"
#允许Cookie跨域, useful
when doing login verification Access-control-allow-credentials: "True"
#允许提交请求的方法, * means all allowed
Access-control-allow-methods:get,post,put , Delete,patch
Initial Project Preparation
To add, for simple cross-domain and Get,head Cross-domain, it's understandable that a simple cross-domain is a content-type and a POST request, but that the POST request is only application/x-www-form-urlencoded, Multipart/form-data or Text/plain on the contrary, is not a simple cross-domain, this cross-domain has a pre-inspection mechanism, said straightforward point, that is, will send two requests, an options request, a real request
Start by creating a new static Web project that defines three types of requests: simple Cross-domain requests, not simple cross-domain requests, and requests with cookie information (do login checksums). The code is as follows:
<! DOCTYPE html> Then start the Web project (a WYSIWYG tool is recommended here: Browser-sync)
Browser-sync start--server--files "*.html"
Next, do the service side thing, create a new SPRINGMVC project, here recommend a Web site that automatically generates spring seed projects: http://start.spring.io/
Seed Project
The project structure is as follows:
Project structure
Introduction of Lombok and guava in Pom.xml
<dependency>
<groupId>com.google.guava</groupId>
<artifactid>guava</ artifactid>
<version>19.0</version>
</dependency>
<dependency>
< groupid>org.projectlombok</groupid>
<artifactId>lombok</artifactId>
<version >1.16.8</version>
</dependency>
Analog Data Source: UserDB
public class UserDB {public
static cache<string, user> UserDB = Cachebuilder.newbuilder (). Expireafterwrite (1 , timeunit.days). Build ();
static {
String id1 = Uuid.randomuuid (). toString ();
String Id2 = Uuid.randomuuid (). toString ();
String ID3 = Uuid.randomuuid (). toString ();
Userdb.put (ID1, New User (ID1, "jear"));
Userdb.put (Id2, New User (Id2, "Tom"));
Userdb.put (ID3, New User (ID3, "Jack"));
}
Writing the sample controller: Usercontroller
@RestController
@RequestMapping ("/users") public
class Usercontroller {
@RequestMapping (method = Requestmethod.get)
list<user> getlist () {return
lists.newarraylist (Userdb.asmap (). values ());
@RequestMapping (method = Requestmethod.post)
list<string> Add (@RequestBody String name) {
if ( Userdb.asmap (). values (). Stream (). AnyMatch (User-> user.getname (). Equals (name)) {return
lists.newarraylist ("Add failed, username '" + name + ' existing ');
}
String id = uuid.randomuuid (). toString ();
Userdb.put (ID, new User (ID, name));
Return Lists.newarraylist ("Add success:" + userdb.getifpresent (ID));
}
Writing the sample controller: Userlogincontroller
@RestController
@RequestMapping ("/user/login") public
class Userlogincontroller {
@RequestMapping ( method = Requestmethod.get)
Object GetInfo (HttpSession session) {
object = Session.getattribute (" Loginer ");
return object = null? Lists.newarraylist ("not Logged in"): Object;
}
@RequestMapping (method = requestmethod.post)
list<string> Login (HttpSession session, @RequestBody String Name) {
optional<user> User = Userdb.asmap (). values (). Stream (). Filter (User1-> user1.getname (). Equals ( Name)). Findany ();
if (User.ispresent ()) {
Session.setattribute ("Loginer", User.get ());
return lists.newarraylist ("Login succeeded!");
}
return lists.newarraylist ("Login failed, user name not found:" + name);
}
Finally start the service side project
MVN Clean Package
Debug Mode boot Application
Here, the main work is done, open the browser, access the static Web project, open the console, and found that the AJAX request can not get the data, this is the same as the same as the origin of the same strategy. Cors Support Corsfilter: Filter phase Cors
@Configuration public class Webconfig extends Webmvcconfigureradapter {@Bean public filterregistrationbean Filte
Rregistrationbean () {//Cors authorization of the response header mycorsregistration corsregistration = new Mycorsregistration ("/**"); Corsregistration.allowedorigins (Crossorigin.default_origins). Allowedmethods (HttpMethod.GET.name ( ), HttpMethod.HEAD.name (), HttpMethod.POST.name (), HttpMethod.PUT.name ()). Allowedheaders (Crossorigin.defa ult_allowed_headers). Exposedheaders (Httpheaders.set_cookie). Allowcredentials (Crossorigin .
default_allow_credentials). MaxAge (Crossorigin.default_max_age);
Register cors filter Urlbasedcorsconfigurationsource Configurationsource = new Urlbasedcorsconfigurationsource ();
Configurationsource.registercorsconfiguration ("/**", Corsregistration.getcorsconfiguration ());
Corsfilter corsfilter = new Corsfilter (Configurationsource); ReturN New Filterregistrationbean (corsfilter); }
}
Now test "simple cross-domain" and "Not simple Cross-domain", and you can already respond correctly
Browser picture
Let's Test the "login check" and "login" to see if the cookie will work across the domain.
Browser picture
If the service-side allowcredentials is set to false, or if the AJAX request does not take {withcredentials:true}, the login checksum is never logged in, because the cookie is not passed between the browser and the server Corsinterceptor: Cors of the Interceptor phase
Now that you have the filter level of cors, why do you have to corsinterceptor? Because the granularity of control is different. Filter is a front filter for any servlet, and Inteceptor is only valid for blocking requests under Dispatcherservlet, which is the last line of defense required to enter handler, and if a layer of inteceptor defense is set up, can enhance security and controllability.
As for the cors at this stage, I had to spit a few sentences, and spring put Corsinteceptor in the last one on the interceptor chain, which means if I had a custom interceptor, the request would be intercepted by my own interceptor, You can only cross the domain through Corsfilter authorization, and you can't go to Corsinterceptor, as for why, the following will be mentioned.
So Corsinterceptor is written specifically for handler across domains in the authorization.
Nonsense not much to say, directly on the code:
@Configuration public class Webconfig extends Webmvcconfigureradapter {@Bean public filterregistrationbean CORSF Ilterregistrationbean () {//Cors Authorization for response headers mycorsregistration corsregistration = new Mycorsregistration ("/*
*");
This._configcorsparams (corsregistration);
Register cors filter Urlbasedcorsconfigurationsource Configurationsource = new Urlbasedcorsconfigurationsource ();
Configurationsource.registercorsconfiguration ("/**", Corsregistration.getcorsconfiguration ());
Corsfilter corsfilter = new Corsfilter (Configurationsource);
return new Filterregistrationbean (Corsfilter); @Override public void Addcorsmappings (Corsregistry registry) {//configure Corsinterceptor cors parameter this
. _configcorsparams (Registry.addmapping ("/**")); } private void _configcorsparams (Corsregistration corsregistration) {corsregistration.allowedorigins (CrossOr Igin. Default_origins). AllowedmethoDS (HttpMethod.GET.name (), HttpMethod.HEAD.name (), HttpMethod.POST.name (), HttpMethod.PUT.name ()). Allowedh Eaders (crossorigin.default_allowed_headers). Exposedheaders (Httpheaders.set_cookie). Allow
Credentials (crossorigin.default_allow_credentials). MaxAge (Crossorigin.default_max_age); }
}
Open the browser, the effect is the same as above @CrossOrigin: Handler stage Cors
If you write the previous code carefully, you should have found this annotation, this annotation is used in the Controller method, in fact, Spring here with the Corsinterceptor, do the last layer of interception, This also explains why Corsinterceptor is always the last interceptor to execute.
This is the minimum control granularity that can be accurate to a request for Cross-domain control
The first two stages of the Webconfig configuration are commented out, and then added to the cross-domain annotation
@CrossOrigin (origins = "http://localhost:3000")
@RequestMapping ( method = Requestmethod.get)
list<user> getlist () {return
lists.newarraylist (Userdb.asmap (). VALUES ()) ;
}
Opens the browser and finds that only the first request can cross the domain correctly
Handler cross-domain summary
The three-phase cors configuration sequence is superimposed to the front, rather than the back completely covered front, so in the design, each stage how to accurately control the cors, but also in practice to explore slowly ... Pursuing a better development experience: consolidating third party Corsfilter
Use and analysis of this class library will be launched in the next chapter
Official website: http://software.dzhuvinov.com/cors-filter.html
The
prefers to use this corsfilter mainly because it supports cors configuration files, can automatically read cors.properties under Classpath, and the feature sample code for file watching downloads http:// Git.oschina.net/jearton/springmvc-cors http://git.oschina.net/jearton/web-demo/
Text/jearton (author of Jane book)
Original link: http://www.jianshu.com/p/d05303d34222
Copyright belongs to the author, reproduced please contact the author to obtain authorization, and labeled "Jane book author."