当前位置: 移动技术网 > IT编程>开发语言>Java > 浅谈Java 三种方式实现接口校验

浅谈Java 三种方式实现接口校验

2019年07月19日  | 移动技术网IT编程  | 我要评论

徐州云龙湖食人鱼,洪晓芸夜半思乳时,英格兰vs哥斯达黎加

本文介绍了java 三种方式实现接口校验,主要包括aop,mvc拦截器,分享给大家,具体如下:

方法一:aop

代码如下定义一个权限注解

package com.thinkgem.jeesite.common.annotation; 
 
import java.lang.annotation.elementtype; 
import java.lang.annotation.retention; 
import java.lang.annotation.retentionpolicy; 
import java.lang.annotation.target; 
 
/** 
 * 权限注解 
 * created by hamming on 2016/12/ 
 */ 
@target(elementtype.method)//这个注解是应用在方法上 
@retention(retentionpolicy.runtime) 
public @interface accesstoken { 
/*  string userid(); 
  string token();*/ 
} 

获取页面请求中的id token

@aspect 
@component 
public class accesstokenaspect { 
 
  @autowired 
  private apiservice apiservice; 
 
  @around("@annotation(com.thinkgem.jeesite.common.annotation.accesstoken)") 
  public object doaccesscheck(proceedingjoinpoint pjp) throws throwable{ 
    httpservletrequest request = ((servletrequestattributes) requestcontextholder.getrequestattributes()).getrequest(); 
    string id = request.getparameter("id"); 
    string token = request.getparameter("token"); 
    boolean verify = apiservice.verifytoken(id,token); 
    if(verify){ 
      object object = pjp.proceed(); //执行连接点方法 
      //获取执行方法的参数 
 
      return object; 
    }else { 
      return resultapp.error(3,"token失效"); 
    } 
  } 
} 

token验证类  存储用到redis

package com.thinkgem.jeesite.common.service; 
 
import com.thinkgem.jeesite.common.utils.jedisutils; 
import io.jsonwebtoken.jwts; 
import io.jsonwebtoken.signaturealgorithm; 
import io.jsonwebtoken.impl.crypto.macprovider; 
import org.slf4j.logger; 
import org.slf4j.loggerfactory; 
import org.springframework.beans.factory.annotation.autowired; 
import org.springframework.stereotype.service; 
import org.springframework.transaction.annotation.transactional; 
import redis.clients.jedis.jedis; 
 
import java.io.*; 
import java.security.key; 
import java.util.date; 
 
/** 
 *token登陆验证 
 * created by hamming on 2016/12/ 
 */ 
@service 
public class apiservice { 
  private static final string at="accesstoken"; 
 
  public static key key; 
 
//  private logger logger = loggerfactorygetlogger(getclass()); 
  /** 
   * 生成token 
   * key以字节流形式存入redis 
   * 
   * @param date 失效时间 
   * @param appid appid 
   * @return 
   */ 
  public string generatetoken(date date, string appid){ 
    jedis jedis = null; 
    try { 
      jedis = jedisutils.getresource(); 
      byte[] buf = jedis.get("api:key".getbytes()); 
      if (buf == null) { // 建新的key 
        key = macprovider.generatekey(); 
        bytearrayoutputstream bao = new bytearrayoutputstream(); 
        objectoutputstream oos = new objectoutputstream(bao); 
        oos.writeobject(key); 
        buf = bao.tobytearray(); 
        jedis.set("api:key".getbytes(), buf); 
      } else { // 重用老key 
        key = (key) new objectinputstream(new bytearrayinputstream(buf)).readobject(); 
      } 
 
    }catch (ioexception io){ 
//      system.out.println(io); 
    }catch (classnotfoundexception c){ 
//      system.out.println(c); 
    }catch (exception e) { 
//      logger.error("apiservice", "generatetoken", key, e); 
    } finally { 
      jedisutils.returnresource(jedis); 
    } 
 
    string token = jwts.builder() 
        .setsubject(appid) 
        .signwith(signaturealgorithm.hs512, key) 
        .setexpiration(date) 
        .compact(); 
    // 计算失效秒,7889400秒三个月 
    date temp = new date(); 
    long interval = (date.gettime() - temp.gettime())/1000; 
    jedisutils.set(at+appid ,token,(int)interval); 
    return token; 
  } 
 
  /** 
   * 验证token 
   * @param appid appid 
   * @param token token 
   * @return 
   */ 
  public boolean verifytoken(string appid, string token) { 
    if( appid == null|| token == null){ 
      return false; 
    } 
    jedis jedis = null; 
    try { 
      jedis = jedisutils.getresource(); 
      if (key == null) { 
        byte[] buf = jedis.get("api:key".getbytes()); 
        if(buf==null){ 
          return false; 
        } 
        key = (key) new objectinputstream(new bytearrayinputstream(buf))readobject(); 
      } 
      jwts.parser().setsigningkey(key).parseclaimsjws(token).getbody().getsubject().equals(appid); 
      return true; 
    } catch (exception e) { 
//      logger.error("apiservice", "verifytoken", key, e); 
      return false; 
    } finally { 
      jedisutils.returnresource(jedis); 
    } 
  } 
 
  /** 
   * 获取token 
   * @param appid 
   * @return 
   */ 
  public string gettoken(string appid) { 
    jedis jedis = null; 
    try { 
      jedis = jedisutils.getresource(); 
      return jedis.get(at+appid); 
    } catch (exception e) { 
//      logger.error("apiservice", "gettoken", e); 
      return ""; 
    } finally { 
      jedisutils.returnresource(jedis); 
    } 
  } 
} 

spring aop配置

<!--aop --> 
<!--   扫描注解bean --> 
<context:component-scan base-package="com.thinkgem.jeesite.common.aspect"/> 
 <aop:aspectj-autoproxy proxy-target-class="true"/> 

验证权限方法使用 直接用注解就可以了accesstoken

例如

package com.thinkgem.jeesite.modules.app.web.pay; 
 
import com.alibaba.fastjson.json; 
import com.thinkgem.jeesite.common.annotation.accesstoken; 
import com.thinkgem.jeesite.common.base.resultapp; 
import com.thinkgem.jeesite.modules.app.service.pay.appalipayconfservice; 
import org.springframework.beans.factory.annotation.autowired; 
import org.springframework.stereotype.controller; 
import org.springframework.web.bind.annotation.requestmapping; 
import org.springframework.web.bind.annotation.requestmethod; 
import org.springframework.web.bind.annotation.responsebody; 
 
import java.util.hashmap; 
import java.util.map; 
 
/** 
 * 支付接口 
 * created by hamming on 2016/12/ 
 */ 
@controller 
@requestmapping(value = "/app/pay") 
public class apppaymodule { 
 
  @autowired 
  private appalipayconfservice appalipayconfservice; 
 
  @requestmapping(value = "/alipay", method = requestmethodpost, produces="application/json") 
  @accesstoken 
  @responsebody 
  public object alipay(string orderid){ 
    if(orderid ==null){ 
      map re = new hashmap<>(); 
      re.put("result",3); 
      re.put("msg","参数错误"); 
      string json = jsontojsonstring(re); 
      return json; 
    }else { 
      return null; 
    } 
  } 
} 

方法二: aop方法2

1.定义一个查询父类,里面包含到authtoken跟usedid两个属性,所有需要校验用户的请求的查询参数都继承这个查询父类,之所以会有这个userid,是因为我们校验得到用户之后,需要根据用户id获取一些用户数据的,所以在aop层我们就回填了这个参数了,这样也不会影响之前的代码逻辑(这个可能跟我的业务需求有关了)

public class authsearchvo {
  
  public string authtoken; //校验字符串
  
  public integer userid; //app用户id
  
  public final string getauthtoken() {
    return authtoken;
  }

  public final void setauthtoken(string authtoken) {
    this.authtoken = authtoken;
  }

  public final integer getuserid() {
    return userid;
  }

  public final void setuserid(integer userid) {
    this.userid = userid;
  }

  @override
  public string tostring() {
    return "searchvo [authtoken=" + authtoken + ", userid=" + userid + "]";
  }

}

2.定义一个方法级的注解,所有需要校验的请求都加上这个注解,用于aop的拦截(当然你也可以拦截所有控制器的请求)

@target(elementtype.method)
@retention(retentionpolicy.runtime)
public @interface authtoken {
string type();
}

3.aop处理,之所以会将注解作为参数传进来,是因为考虑到可能会有多个app的校验,可以利用注解的type属性加以区分

public class authtokenaopinterceptor {

@resource
private appuserservice appuserservice;

private static final string authfieldname = "authtoken";
private static final string useridfieldname = "userid";

public void before(joinpoint joinpoint, authtoken authtoken) throws throwable{

  object[] args = joinpoint.getargs(); //获取拦截方法的参数
  boolean isfound = false;
  for(object arg : args){
    if(arg != null){
      class<?> clazz = arg.getclass();//利用反射获取属性值
      field[] fields = clazz.getdeclaredfields();
      int authindex = -1;
      int useridindex = -1;
      for(int i = 0; i < fields.length; i++){
        field field = fields[i];
        field.setaccessible(true);
        if(authfieldname.equals(field.getname())){//包含校验token
          authindex = i;
        }else if(useridfieldname.equals(field.getname())){//包含用户id
          useridindex = i;
        }
      }

      if(authindex >= 0 & useridindex >= 0){
        isfound = true;
        authtokencheck(fields[authindex], fields[useridindex], arg, authtoken);//校验用户
        break;
      }
    }
  }
  if(!isfound){
    throw new bizexception(errormessage.check_authtoken_fail);
  }

}

private void authtokencheck(field authfield, field useridfield, object arg, authtoken authtoken) throws exception{
  if(string.class == authfield.gettype()){
    string authtokenstr = (string)authfield.get(arg);//获取到校验token
    appuser user = appuserservice.getuserbyauthtoken(authtokenstr);
    if(user != null){
      useridfield.set(arg, user.getid());
    }else{
      throw new bizexception(errormessage.check_authtoken_fail);
    }
  }

}
}

4.最后就是在配置文件中配置这个aop了(因为我们的spring版本跟aspect版本有点出入,导致用不了基于注解的方式)

<bean id="authtokenaopinterceptor" class="com.distinct.app.web.common.auth.authtokenaopinterceptor"/>
<aop:config proxy-target-class="true">
  <aop:pointcut id="authcheckpointcut" expression="@annotation(authtoken)"/>
  <aop:aspect ref="authtokenaopinterceptor" order="1">
    <aop:before method="before" pointcut-ref="authcheckpointcut"/>
  </aop:aspect>
</aop:config>

最后给出测试代码,这样的代码就优雅很多了

@requestmapping(value = "/appointments", method = { requestmethod.get })
@responsebody
@authtoken(type="disticntapp")
public list<appointmentvo> getappointments(appointmentsearchvo appointmentsearchvo) {
  list<appointmentvo> appointments = appointmentservice.getappointment(appointmentsearchvo.getuserid(), appointmentsearchvo);
  return appointments;
}

方法三: mvc拦截器

服务器:

拼接token之外所有参数,最后拼接token_key,做md5,与token参数比对

如果token比对失败返回状态码 500

public class apiinterceptor extends handlerinterceptoradapter { 
 
  @override 
  public boolean prehandle(httpservletrequest request, 
      httpservletresponse response, object handler) throws exception { 
    log.info(request); 
     
    string token = request.getparameter("token"); 
     
    // token is not needed when debug 
    if(token == null) return true; // !! remember to comment this when deploy on server !! 
     
    enumeration parakeys = request.getparameternames(); 
    string encodestr = ""; 
    while (parakeys.hasmoreelements()) { 
      string parakey = (string) parakeys.nextelement(); 
      if(parakey.equals("token"))  
        break; 
      string paravalue = request.getparameter(parakey); 
      encodestr += paravalue; 
    } 
    encodestr += default.token_key; 
    log.out(encodestr); 
     
    if ( ! token.equals(digestutils.md5hex(encodestr))) { 
      response.setstatus(500); 
      return false; 
    } 
     
    return true; 
  } 
 
  @override 
  public void posthandle(httpservletrequest request, 
      httpservletresponse response, object handler, 
      modelandview modelandview) throws exception { 
    log.info(request); 
  } 
 
  @override 
  public void aftercompletion(httpservletrequest request, 
      httpservletresponse response, object handler, exception ex) 
      throws exception { 
     
  } 
} 

spring-config.xml配置中加入

<mvc:interceptors> 
  <mvc:interceptor> 
    <mvc:mapping path="/api/*" /> 
    <bean class="cn.web.interceptor.apiinterceptor" /> 
  </mvc:interceptor> 
</mvc:interceptors> 

客户端:

拼接请求接口的所有参数,最后拼接token_key,做md5,作为token参数

请求样例:http://127.0.0.1:8080/interface/api?key0=param0&key1=param1&token=md5(concat(param0, param1))

api测试页面,用到了bootstrap和angularjs,还有一个js的hex_md5函数

<!doctype html> 
<html ng-app> 
<head> 
  <meta charset="utf-8"> 
  <title>api test</title> 
  <link href="../css/bootstrap.min.css" rel="external nofollow" rel="stylesheet"> 
  <script src="../js/md5.min.js"></script> 
  <script src="../js/angular.min.js"></script> 
  <script> 
    function api(url){ 
      this.url = arguments[0]; 
      this.params = array.prototype.slice.call(arguments, 1, arguments.length); 
      this.request = function(params){ 
        var addr = url; 
        var values = array.prototype.slice.call(arguments, 1, arguments.length); 
        if(params[0] != undefined && values[0] != undefined && values[0] != '') 
          addr += '?' + params[0] + "=" + values[0]; 
        for(var i=1; i < valueslength; i++) 
          if(params[i] != undefined && values[i] != undefined && values[i] != '') 
            addr += "&" + params[i] + "=" + values[i]; 
        return addr; 
      } 
    } 
     
    function apilistctrl($scope) { 
      $scope.md5 = hex_md5; 
      $scope.token_key = "9ae5r06fs8"; 
      $scope.concat = function(){ 
        var args = array.prototype.slice.call(arguments, 0, arguments.length); 
        args.push($scope.token_key); 
        return args.join(""); 
      } 
       
      $scope.apilist = [ 
       
      new api("account/login", "username", "pwd"), 
      new api("account/register", "username", "pwd", "tel", "code"), 
       
      ] ; 
    } 
  </script> 
</head> 
<body> 
 
  <div ng-controller="apilistctrl"> 
    <div> search: <input type="text" ng-model="search"><hr> 
    token_key <input type="text" ng-model="token_key"> 
    md5 <input type="text" ng-model="str"> {{md5(str)}} 
    </div> 
    <hr> 
    <div ng-repeat="api in apilist | filter:search" > 
      <form action="{{api.url}}" method="post"> 
      <a href="{{api.request(api.params, value0, value1, value2, value3, value4, value5, value6, value7, value8, value9)}}" rel="external nofollow" > 
      {{api.request(api.params, value0, value1, value2, value3, value4, value5, value6, value7, value8, value9)}} 
      </a> 
      <br> 
      {{concat(value0, value1, value2, value3, value4, value5, value6, value7, value8, value9)}} 
      <br> 
      {{api.params[0]}} <input id="{{api.params[0]}}" name="{{api.params[0]}}" ng-model="value0" ng-hide="api.params[0]==undefined"> 
      {{api.params[1]}} <input id="{{api.params[1]}}" name="{{api.params[1]}}" ng-model="value1" ng-hide="api.params[1]==undefined"> 
      {{api.params[2]}} <input id="{{api.params[2]}}" name="{{api.params[2]}}" ng-model="value2" ng-hide="api.params[2]==undefined"> 
      {{api.params[3]}} <input id="{{api.params[3]}}" name="{{api.params[3]}}" ng-model="value3" ng-hide="api.params[3]==undefined"> 
      {{api.params[4]}} <input id="{{api.params[4]}}" name="{{api.params[4]}}" ng-model="value4" ng-hide="api.params[4]==undefined"> 
      {{api.params[5]}} <input id="{{api.params[5]}}" name="{{api.params[5]}}" ng-model="value5" ng-hide="api.params[5]==undefined"> 
      {{api.params[6]}} <input id="{{api.params[6]}}" name="{{api.params[6]}}" ng-model="value6" ng-hide="api.params[6]==undefined"> 
      {{api.params[7]}} <input id="{{api.params[7]}}" name="{{api.params[7]}}" ng-model="value7" ng-hide="api.params[7]==undefined"> 
      {{api.params[8]}} <input id="{{api.params[8]}}" name="{{api.params[8]}}" ng-model="value8" ng-hide="api.params[8]==undefined"> 
      {{api.params[9]}} <input id="{{api.params[9]}}" name="{{api.params[9]}}" ng-model="value9" ng-hide="api.params[9]==undefined"> 
      token <input id="token" name="token" value="{{md5(concat(value0, value1, value2, value3, value4, value5, value6, value7, value8, value9))}}"> 
      <input type="submit" class="btn" ng-hide="api.params[0]==undefined"> 
      </form> 
      <hr> 
    </div> 
  </div> 
 
</body> 
</html> 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网