Spring Boot Architecture Design--Permission validation and API interface Unified return format

Source: Internet
Author: User

It took a day of fighting yesterday to take care of it and record it.

Permission validation

The permission validation implementation needs to intercept the request parameter, which is very simple and can be implemented using Interceptor,aspect,filter in Springboot. The realization of a lot of online, it is too lazy to write, the key word search is.

After the request parameter is obtained, the sign value is calculated according to the rules you define, for example, the token+timestamp+ logical method parameter dictionary is sorted after the MD5+BASE64 bit, and then compared with the sign value passed by the client.

API Interface Unified return format

This is the thing to toss people, in net implementation of the time feel quite simple, in spring boot under the dead.

The purpose of the unified return format is to decouple the logical method from the system return format. For example, the API interface return format is as follows:

// permission validation failed to return {    "data"null,    "code"  1,    "msg"" server permission validation failed " }
// The return of an unhandled exception event occurred {    "data"null,    "code" :-1,    "msg"" server exception, please try again later " }
//Request returned successfully{    "Data": {        "ID":1,        "userid":"test1",        "name":"Sun Yang",        "Phone":"183*******",        "sourcetype":1,        "LoginName":"test1",        "loginpwd":"test1",        "Powertype":1,        "Registertime":"2017-10-19"    },    "Code":10000,    "msg":""}

This format consists of 2 parts, the first part is the outermost data,code,msg. I call it a system-level return parameter, and data is a method-level return parameter. The processing logic is to capture the logical method return value and then convert it back to the standard format returned to the client.

The problem with spring boot is that interceptor cannot get the return value, Restapi request, Modelandview This parameter returns NULL, and cannot remove the return value from the response parameter. Google Baidu for an afternoon, and finally give up.

Then choose the aspect way, using round annotations, very easy to get the return value, everything looks very smooth, the result in the change in the return value, error ... Because the response is generated, the aspect execution sequence precedes the servlet, the logical method returns model, then aspect executes, and the servlet executes, and the servlet defaults to serialize the return value based on the return value of the logical method. At this point, because I have modified the return value type in aspect, a type conversion error occurs. Aspect not reach the goal, also declared abandoned.

Finally see the outside network a netizen suggested using filter. Filter execution sequence after servlet, try, OK, can capture, can modify. There is a problem, however, because it is executed after the servlet, and the servlet defaults to serializing the return value of the logical method ... So the data parameter inside is a string, and then the filter returns the time to serialize once again, the information format is terrible, the client is not to scold death ah. Lazy late at night, do not want to be tired, directly to the obtained logical method of the JSON string is deserialized into an object, and then assembled into the data, and then the filter parameter serialization ... The effect of the last interface is to look at the current appearance, low efficiency, to achieve the minimum effect requirements, the future is free to optimize it ... Paste the code below

Filter Code:

/** * @authorSun Yang * @date Created in PM 6:01 17/10/19*/@WebFilter (FilterName= "Global Filter", Urlpatterns = "/*") Public classGlobalfilterImplementsFilter {Private FinalString jsonarraysign = "["; Private Final BooleanDEBUG =true; @Override Public voidInit (Filterconfig filterconfig)throwsservletexception {} @Override Public voidDoFilter (ServletRequest servletrequest, Servletresponse servletresponse, Filterchain filterch Ain)throwsIOException, servletexception {responsemodel response=NewResponsemodel (); Logutil Logger=NewLogutil (); StringBuilder SB=NewStringBuilder (); Gson Gson=NewGsonbuilder (). Serializenulls (). Create (); //permission Check ParametersString token = ""; String timestamp= ""; String Path= ""; String Sign= ""; HttpServletRequest Request=(httpservletrequest) ServletRequest; String[] Paths= Request.getrequesturl (). toString (). Split ("/api/sx"); if(Paths.length > 1) {Path= Paths[1]; }        LongStartTime =System.currenttimemillis (); Sb.append ("\ n Path:" + request.getrequesturl () + "\ n"); Sb.append ("Method:" + request.getmethod () + "\ n"); Sb.append ("QueryString:" + request.getquerystring () + "\ n"); Sb.append ("Request parameter: \ n"); Enumeration<String> paras =Request.getparameternames ();  while(Paras.hasmoreelements ()) {String name=paras.nextelement (); String value=Request.getparameter (name); if("token". Equals (name)) {token=value; }            if("Timestamp". Equals (name)) {Timestamp=value; }            if("Sign". Equals (name)) { Sign=value; } sb.append (Name+ ":" + value + "\ n"); }        if(! DEBUG &&!sign.equals (authverificationutil.countsign (token, timestamp, path)) {Sb.append ("Method Time:" + (System.currenttimemillis ()-StartTime) + "MS \ n");            Response.setcode (codetable.accessdenied); Response.setmsg ("Server Permission validation failed"); Response.setdata (NULL); Sb.append ("Logic Error:" + "server permission validation failed: Token:" + token + "Timestamp:" + timestamp + "path:" +Path+ "Server-side sign:" +authverificationutil.countsign (token, timestamp, path));        Logger.error (Sb.tostring ()); } Else{myresponsewrapper Responsewrapper=NewMyresponsewrapper ((httpservletresponse) servletresponse); Try{filterchain.dofilter (ServletRequest, Responsewrapper); String responsecontent=NewString (Responsewrapper.getdatastream ()); //determine if the return value is Jsonobject or Jsonarray                if(Responsecontent.startswith (jsonarraysign)) {Response.setdata (NewJsonparser (). Parse (responsecontent). Getasjsonarray ()); } Else{response.setdata (NewJsonparser (). Parse (responsecontent). Getasjsonobject ());                } response.setcode (codetable.success); Response.setmsg (""); Sb.append ("Method Time:" + (System.currenttimemillis ()-StartTime) + "MS \ n"); Sb.append ("Response parameter:" +responsecontent);            Logger.info (Sb.tostring ()); } Catch(Exception e) {sb.append ("Method Time:" + (System.currenttimemillis ()-StartTime) + "MS \ n"); if(Einstanceofmyexception)                    {Response.setcode (((myexception) e). GetCode ());                    Response.setmsg (((myexception) e). getmsg ()); Response.setdata (NULL); Sb.append ("Logic error:" +((myexception) e). GetLog ());                Logger.error (Sb.tostring ()); } Else{response.setcode (codetable.unknowerror); Response.setmsg ("Server exception, please try again later"); Response.setdata (NULL); Sb.append ("Uncaught exception:" +e.getmessage ());                Logger.error (Sb.tostring ()); }}} ((HttpServletResponse) servletresponse). SetHeader ("Content-type", "Application/json;charset=utf-8");    Servletresponse.getoutputstream (). Write (Gson.tojson (response). GetBytes ()); } @Override Public voiddestroy () {}}

The logical method is similar to the following:

    @RequestMapping ("Login")    public  User Login (Loginmodel loginmodel) {        =  Userrepository.findbyloginnameandloginpwd (Loginmodel.getloginname (), loginmodel.getloginpwd ());         if NULL             {thrownew myexception (10001, "username or password is incorrect");        }         return user;    }

Toss so many things, the purpose is to completely simplify the logic method code difficulty ~ Define the interface document and path, the logic code can be written to the intern, and can be lazy ~ ~

There are also 2 auxiliary classes I would like to post:

 Public classMyresponsewrapperextendshttpservletresponsewrapper {bytearrayoutputstream output;    Filterservletoutputstream Filteroutput;  PublicMyresponsewrapper (httpservletresponse response) {Super(response); Output=NewBytearrayoutputstream (); } @Override PublicServletoutputstream Getoutputstream ()throwsIOException {if(Filteroutput = =NULL) {Filteroutput=Newfilterservletoutputstream (output); }        returnFilteroutput; }     Public byte[] Getdatastream () {returnOutput.tobytearray (); }}
 Public classFilterservletoutputstreamextendsservletoutputstream {dataoutputstream output;  Publicfilterservletoutputstream (OutputStream output) { This. Output =Newdataoutputstream (output); } @Override Public voidWriteintARG0)throwsIOException {output.write (arg0); } @Override Public voidWritebyte[] arg0,intArg1,intARG2)throwsIOException {output.write (arg0, arg1, arg2); } @Override Public voidWritebyte[] arg0)throwsIOException {output.write (arg0); } @Override Public BooleanIsReady () {return false; } @Override Public voidSetwritelistener (Writelistener writelistener) {}}

Spring Boot Architecture Design--Permission validation and API interface Unified return format

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.