> Java > java지도 시간 > 본문

Java에서 인터페이스 검증을 구현하는 세 가지 방법

黄舟
풀어 주다: 2017-10-19 09:29:08
원래의
2021명이 탐색했습니다.

이 글에서는 주로 Java에서 인터페이스 검증을 구현하는 세 가지 방법을 소개합니다. 편집자는 이것이 꽤 좋다고 생각하므로 지금 공유하고 참고용으로 제공하겠습니다. 에디터와 함께 살펴보세요

이 기사에서는 주로 AOP 및 MVC 인터셉터를 포함하여 Java에서 인터페이스 검증을 구현하는 세 가지 방법을 소개합니다. 자세한 내용은 다음과 같습니다.

방법 1: 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 토큰 가져오기


@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; 
    } 
  } 
}
로그인 후 복사

방법 2: AOP 방법 2

1이라는 두 가지 속성을 포함하는 쿼리 상위 클래스를 정의합니다. 모두 필수 사용자 요청을 확인하기 위한 쿼리 매개변수는 모두 이 쿼리 상위 클래스를 상속합니다. 이 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를 구성하는 것입니다(스프링 버전은 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;
}
로그인 후 복사

방법 3: MVC 인터셉터

서버:

모든 매개변수 연결 토큰을 제외하고 마지막으로 token_key를 연결합니다. MD5를 수행하고 토큰 매개변수와 비교합니다

토큰 비교에 실패하면 상태 코드 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를 만들어 토큰 매개변수로 사용합니다

요청 예: 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] != &#39;&#39;) 
          addr += &#39;?&#39; + params[0] + "=" + values[0]; 
        for(var i=1; i < valueslength; i++) 
          if(params[i] != undefined && values[i] != undefined && values[i] != &#39;&#39;) 
            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> 
 
  <p ng-controller="APIListCtrl"> 
    <p> 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)}} 
    </p> 
    <hr> 
    <p 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> 
    </p> 
  </p> 
 
</body> 
</html>
로그인 후 복사
를 사용합니다.

위 내용은 Java에서 인터페이스 검증을 구현하는 세 가지 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿