软件编程
位置:首页>> 软件编程>> java编程>> 浅谈Java 三种方式实现接口校验

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

作者:BarryW  发布时间:2023-01-20 02:57:55 

标签:java,接口,校验

本文介绍了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>

来源:http://www.cnblogs.com/barrywxx/p/6964423.html

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com