Java HTTP Interface Signature Verification instance __java

Source: Internet
Author: User
first, the business background

Call the third party interface or the front and back end separation development, call the business interface to prevent brush/violation calls and other phenomena need to add verification mechanism, such as the payment class interface, both sides in order to ensure that the data parameters in the transmission process has not been tampered with, the interface data need to be countersigned, and then on the interface server side of the interface parameters for verification, Make sure that the two signatures are the same, and then do business logic processing after verification.

second, processing ideas

The general direction of signature verification is nothing more than: the client and the service end agreed, according to the unified algorithm, unified parameters, unified order, the unified key for encryption, and then compare; I'm here to introduce a simple and practical and commonly used signature/verification method ideas:
Client:
The signature is uploaded to the server via header, key named: Token
Signature: API version number +ak+ signature Expiration time + key (SK) +url+requestmethod+ client ordered parameters are encrypted;

Encryption algorithm: MD5;
Key (SK): The front and back end is unified, the signature is encrypted when used equivalent to adding salt;
AK: Multi-client use of different SK, the service end need to find the corresponding through AK SK for encryption verification;
Signature expiration: The client-defined signature expiration time, which does not pass the signature request;

Request parameters: Sorted parameters are uploaded to the server via Request-line or request-body

server-side:
      Signature, validation in the same way. To confirm that the caller is legitimate, this is the idea of interface signature verification. The
server-side code is as follows (for reference only):     Through the Spring Interceptor Handlerinterceptor (which converts the request body parameter to the line argument, so, directly getparameter)

/** * @Description: Verification interception * @Author Pengju * @date 2018/4/11 13:44/public class Apiakskinterceptor implements H

    Andlerinterceptor {private final Logger Logger = Loggerfactory.getlogger (Apiakskinterceptor.class);

    @Autowired private Baseopenapiconfig Baseopenapiconfig; /** * Intercept The execution of a handler. Called after Handlermapping determined * A appropriate handler object but before Handleradapter invokes
     . * <p>dispatcherservlet processes a handler in the execution chain, consisting * of any number of interceptors, W
     ITH the handler itself at the end. * with it, each interceptor can decide to abort the execution chain, * typically sending a HTTP error or WRI
     Ting a custom response. * <p><strong>Note:</strong> Special considerations apply for Asynchronous * request processing.
     For more details, * {@link asynchandlerinterceptor}. * @param request Current HTTP request * @param response Current HTTP response * @param handler chosen handler to execute, for Typ e and/or instance evaluation * @return {@code true} if the execution chain should proceed with the * next INTERC Eptor or the handler itself.
     Else, Dispatcherservlet assumes * that is interceptor has already dealt with the response. * @throws Exception in case of errors */@Override public boolean prehandle (HttpServletRequest request, HttpS Ervletresponse response, Object handler) throws Exception {if (handler = NULL | |!) (
        Handler instanceof Handlermethod)) {return true;
        } Handlermethod Handlermethod = (handlermethod) handler; if (Handlermethod.getbeantype (). Isannotationpresent (apiaksknotvalidator.class) | | Handlermethod.getmethod (
        ). Isannotationpresent (Apiaksknotvalidator.class)) {return true; Final Long BT = System.currenttimemillis (); Response.AddHeader (HTTP.
        Content_Type, "Application/json;charset=utf-8");
            try {//Get header token String RequestUri = Request.getrequesturi ();
            Final String Requestmethod = Request.getmethod ();
            Final String token = Request.getheader (Tokenhelper.x_ibee_auth_token); Logger.info ("Checkapiaksktoken:check token,request uri={},method={},header token={}", RequestUri, RequestMethod,
            token); Token if (Stringutils.isblank (token) | | | token.split ("-"). Length!= 4) {Logger.error ("check
                Apiaksktoken:token invalid,head key={},token={} ", Tokenhelper.x_ibee_auth_token, token); Resultbean result = new Resultbean (CommonEnum.ResponseEnum.AKSK_ERROR.getCode (), CommonEnum.ResponseEnum.AKSK_
                Error.getmsg (), NULL);
            return Baseopenapiconfig.ajaxtimeout (result, response); }//Check AK value final String AK = token.split ("-")[1];
                if (Stringutils.isblank (AK)) {Logger.error ("Checkapiaksktoken:ak is blank,token={}", token); Resultbean result = new Resultbean (CommonEnum.ResponseEnum.AKSK_ERROR.getCode (), CommonEnum.ResponseEnum.AKSK_ERROR
                . getmsg (), NULL);
            return Baseopenapiconfig.ajaxtimeout (result, response);
            }//Get request body String Jsonreqbody = Parameter2json (request); Final String askreqbody = BaseOpenApiConfig.BLANK_JSON.equals (jsonreqbody)?
            Null:jsonreqbody;
            Final String querystr = request.getquerystring ();
            Check SK value final String SK = Baseopenapiconfig.getskvalue (AK);
                if (Stringutils.isblank (SK)) {Logger.error ("Checkapiaksktoken:sk is blank,ak={}", AK); Resultbean result = new Resultbean (CommonEnum.ResponseEnum.AKSK_ERROR.getCode (), CommonEnum.ResponseEnum.AKSK_
                Error.getmsg (), NULL);return Baseopenapiconfig.ajaxtimeout (result, response);  }//Do check if (!new tokenhelper (AK, SK). Verifytoken (token, RequestUri, Requestmethod, Querystr,  Askreqbody)) {logger.error ("Checkapiaksktoken:token Invalid,do not access,uri={},token={}", RequestUri,
                token); Resultbean result = new Resultbean (CommonEnum.ResponseEnum.AKSK_ERROR.getCode (), CommonEnum.ResponseEnum.AKSK_
                Error.getmsg (), NULL);
            return Baseopenapiconfig.ajaxtimeout (result, response);
            }//Set response header Response.AddHeader (Tokenhelper.x_ibee_auth_token, TOKEN);
        return true;
            catch (Exception e) {logger.error ("Checkapiaksktoken:catch e.", e); Resultbean result = new Resultbean (CommonEnum.ResponseEnum.AKSK_ERROR.getCode (), CommonEnum.ResponseEnum.AKSK_
            Error.getmsg (), NULL);
        return Baseopenapiconfig.ajaxtimeout (result, response); } finally {logger.debug ("Checkapiaksktoken:sn={},end,use time={}ms.", BT, (System.currenttimemillis ()-BT)); }/** * Intercept the execution of a handler.
     Called after Handleradapter actually * invoked the handler but the before the view.
     * Can expose additional model objects to the view via the given Modelandview. * <p>dispatcherservlet processes a handler in the execution chain, consisting * of any number of interceptors, W
     ITH the handler itself at the end. * with it, each interceptor can post-process a execution, * getting applied in inverse order of the Executi
     On chain. * <p><strong>Note:</strong> Special considerations apply for Asynchronous * request processing.
     For more details, * {@link asynchandlerinterceptor}. * @param request Current HTTP request * @param response Current HTTP response * @param handlEr handler (or {@link Handlermethod}) that started asynchronous * execution, for type and/or                     Instance examination * @param modelandview the {@code Modelandview} that handler returned * (can also is {@code null}) * @throws Exception in case of errors */@Override public void Posthandl E (httpservletrequest request, httpservletresponse response, Object handler, Modelandview Modelandview) throws Exception {}/** * Callback after completion of request processing, which is, after rendering * the view.
     would be called to any outcome of handler execution, thus allows * for proper resource. * <p>note:will Only is called if this interceptor ' s {@code Prehandle} * method has successfully completed and
     Returned {@code true}! * <p>as with the {@code Posthandle} method, the "method would be" invoked on each * interceptor in the chain in re Verse order, so the FIrst Interceptor would be * is invoked. * <p><strong>Note:</strong> Special considerations apply for Asynchronous * request processing.
     For more details, * {@link asynchandlerinterceptor}. * @param request Current HTTP request * @param response Current HTTP response * @param handler Handler (or {@link Handlermethod}) that started asynchronous * execution, for type and/or instance
    n * @param ex exception thrown on handler execution, if all * @throws exception in case of errors * * @Override public void Aftercompletion (HttpServletRequest request, httpservletresponse response, Object handler, Ex Ception ex) throws Exception {}/** * Copy a request map */@SuppressWarnings ("unchecked") publi C Static String Parameter2json (HttpServletRequest request) {linkedhashmap<string, string> linkmap = new Lin
Kedhashmap<> ();        Enumeration<string> enu = request.getparameternames ();
            while (Enu.hasmoreelements ()) {String paraname = enu.nextelement ();
            String value = Request.getparameter (Paraname);
            Linkmap.put (paraname, value);
        System.out.println (Paraname + ":" + value);
    Return jsonobject.tojsonstring (LINKMAP);
 }

}

Akskconfig:

/** * @Description: Akskconfig * @Author Pengju * @date 2018/4/11 13:32/@Component public class Baseopenapicon


    Fig {private static final Logger Logger = Loggerfactory.getlogger (Baseopenapiconfig.class);

    @Value ("${api.ak.sk}") Private String Key_api_ak_sk;
    Public final static String Blank_json = "{}";

    Public final static map<string, string> Akskmap = new concurrenthashmap<> ();
        @PostConstruct public void Initakskmap () {string[] Aksksarray = Key_api_ak_sk.split ("#");
        if (Arrayutils.isempty (Aksksarray)) {Logger.error ("Initakskmap:aksksarray is empty");
            for (String Aksk:aksksarray) {string[] Akskarray = Aksk.split (":"); if (Arrayutils.isempty (akskarray) && Akskarray.length < 2) {Logger.error ("Initakskmap:akskarr
                Ay is error ");
            Continue
            } String Localak = akskarray[0]; String LocalSk = akskarray[1];
        Akskmap.put (Localak, Localsk);
        } public static String Streamtostr (Final boolean closereader, BufferedReader reader) throws IOException {
        if (reader = = null) {return null;
        } String InLine;
        String str = "";
            try {while (InLine = Reader.readline ())!= null) {str + = InLine;
        return str;
            finally {if (Closereader) {reader.close (); 
            }} public string Getskvalue (final String ak) throws Exception {if (Stringutils.isblank (AK)) {
            Logger.error ("Getskvalue:ak is blank");
        return null;
    Return Akskmap.get (AK);
        public static string getsignerrormsg (final Reloadableresourcebundlemessagesource messagesource, String errorkey) { if (Messagesource!= null) {Locale Locale = Localecontextholder.getlocale();
            if (locale = = null) {locale = Locale.simplified_chinese;
        Return messagesource.getmessage (Errorkey, NULL, locale);
    Return "Error Msg"; public static Boolean ajaxtimeout (Resultbean result, httpservletresponse response) {Response.setcharactere
        Ncoding ("UTF-8"); Response.setcontenttype ("Application/json;
        Charset=utf-8 ");
        Response.setheader ("Pragma", "No-cache");
        Response.setheader ("Cache-control", "No-cache");
        Response.setheader ("Cache-control", "No-store");
        Response.setdateheader ("Expires", 0);
        String JSON = Jsonutil.objecttojson (result);
        Response.setheader ("X-response-json", Json);
        Logger.info ("------------ajaxtimeoutresponse:logs--------------");
        Logger.info (JSON);
    return false; }

}
Signature:
/** * @Description: Signature Tool * @Author Pengju * @date 2018/4/11 13:34 * * public class Tokenhelper {private Stati

    C final Logger Logger = Loggerfactory.getlogger (Tokenhelper.class);

    Private String AccessKey;

    Private String Secretkey;

    private static final String token_version = "V2";

    public static final String X_ibee_auth_token = "X-ibeeauth-token";

    Private final list<string> allowedmethods = arrays.aslist ("Get", "POST", "put", "DELETE", "Head");
        Public Tokenhelper () {} public Tokenhelper (string ak, String sk) {This.accesskey = AK;
    This.secretkey = SK;  /** * Generate the token according the request or response contents * * @param urlpath the URL of                   Request * @param method request method, must is one of ' get ', ' POST ', ' DELETE ', ' head ', * "Put" * @param queryparam the query string of request * @param body the Post body for request, or respons E Body * @param expiretime The token expired time * @return The token/public String Generatetoken (Str ing URLPath, string method, String Queryparam, string body, int expiretime) {if (AccessKey = = NULL | | accesskey.i Sempty () | | Secretkey = = NULL | |
        Secretkey.isempty ()) {throw new IllegalArgumentException ("Invalid AK or SK");
        } if (URLPath = null | | urlpath.isempty ()) {throw new IllegalArgumentException ("Empty URL path"); } if (!allowedmethods.contains (method)) {throw new IllegalArgumentException ("Invalid request m
        Ethod ");
        } String token; try {//|v2-{ak}-{expiretime}|{
            sk}| StringBuffer sbsign = new StringBuffer (String.Format ("|%s-%s-%d|%s|", Token_version, AccessKey, Expiretime, SecretKey)

            );
            {urlpath}|

            Sbsign.append (DecodeUtf8 (URLPath)). Append ("|");
            {method}| Sbsign.append (method). AppEnd ("|");
            {queryparam}|
                if (Stringutils.isnoneblank (Queryparam)) {list<string> Qsarray = new arraylist<string> ();
                    For (String kv:queryParam.split ("&")) {string[] t = kv.split ("="); if (T.length > 1) {qsarray.add (String.Format ("%s=%s", DecodeUtf8 (t[0)), DecodeUtf8 (t[1)
                    )));
                    else {Qsarray.add (String.Format ("%s=", DecodeUtf8 (t[0)));
                } collections.sort (Qsarray);
                Boolean-i = true;
                    for (String S:qsarray) {if (i) {i = false;
                    else {sbsign.append ("&");
                } sbsign.append (s);

            } sbsign.append ("|");
            {body}|if (Stringutils.isnoneblank) {sbsign.append (body);

            } sbsign.append ("|");
            MessageDigest digest = messagedigest.getinstance ("MD5");
            Digest.reset ();

            Digest.update (Sbsign.tostring (). GetBytes ("UTF-8"));  V2-{ak}-{expiretime}-{signature} token = String.Format ("%s-%s-%s-%s", Token_version, AccessKey, Expiretime,
        New String (Hex.encodehex (Digest.digest ()));
            catch (Exception e) {logger.error ("failed to decode URL or query path,e.msg={}", E.getmessage ());
        throw new IllegalStateException ("Bad encoded URL path or query string");
    return token;
        private static string DecodeUtf8 (string url) {try {return Urldecoder.decode (URL, "UTF-8");
        catch (Unsupportedencodingexception var2) {return URL; }/** * Verify the token * * @param token the token for VERification * @param urlpath the URL of Request * @param method request method, must being one of ' get ', ' POS T ', ' DELETE ', ' head ', # ' put ' * @param queryparam the query string of request * @param bo Dy the post body to request, or response body */public Boolean Verifytoken (string token, String URLPath, String method, String Queryparam, string body) {if (Stringutils.isblank (token)) {Logger.warn ("token
            Is null ");
        return false;
            try {string[] tokenparts = Token.split ("-");
                if (tokenparts.length!= 4) {Logger.warn ("Invalid token format");
            return false; } if (!
                Token_version.equals (Tokenparts[0])) {Logger.warn ("Invalid TOKEN protocol VERSION");
            return false;
            int expiretime = Integer.parseint (tokenparts[2]); if (Expiretime < SysTem.currenttimemillis ()/1000) {Logger.warn ("expired token");
            return false;
            String tokenverify = Generatetoken (URLPath, method, Queryparam, body, expiretime);
            if (Token.equals (tokenverify)) {return true;
        The catch (Exception e) {logger.error ("Failed to parse token ' {} ', e.msg={}", token, e.getmessage ());
    return false;
    Public String Getaccesskey () {return accessKey;
    } public void Setaccesskey (String accessKey) {this.accesskey = AccessKey;
    Public String Getsecretkey () {return secretkey;
    } public void Setsecretkey (String secretkey) {this.secretkey = Secretkey;
 }
}


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.