欢迎来到高博应诺!
0512-62955981
高博应诺

Java的三种接口校验

2019-03-02 60
方法一:AOP
代码如下定义一个权限注解
?
[java] view plain copy?
?
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/26.?
?*/ ?
@Target(ElementType.METHOD)//这个注解是应用在方法上 ?
@Retention(RetentionPolicy.RUNTIME) ?
public @interface AccessToken { ?
/* ? ?String userId();?
? ? String token();*/ ?
} ?
获取页面请求中的ID token
[java] view plain copy?
?
@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
?
[java] view plain copy?
?
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/23.?
?*/ ?
@Service ?
public class ApiService { ?
? ? private static final String at="accessToken"; ?
??
? ? public static Key key; ?
??
// ? ?private Logger logger = LoggerFactory.getLogger(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配置?
[html] view plain copy?
?
?
?
?
?


验证权限方法使用 直接用注解就可以了AccessToken
例如
?
[java] view plain copy?
?
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/27.?
?*/ ?
@Controller ?
@RequestMapping(value = "/app/pay") ?
public class AppPayModule { ?
??
? ? @Autowired ?
? ? private AppAlipayConfService appAlipayConfService; ?
??
? ? @RequestMapping(value = "/alipay", method = RequestMethod.POST, 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 = JSON.toJSONString(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版本有点出入,导致用不了基于注解的方式)


? ?
? ?
? ? ? ?
? ?


??最后给出测试代码,这样的代码就优雅很多了
@RequestMapping(value = "/appointments", method = { RequestMethod.GET })
@ResponseBody
@AuthToken(type="disticntApp")
public List getAppointments(AppointmentSearchVo appointmentSearchVo) {
? ? List appointments = appointmentService.getAppointment(appointmentSearchVo.getUserId(), appointmentSearchVo);
? ? return appointments;
}
方法三: MVC拦截器
服务器:
拼接token之外所有参数,最后拼接token_key,做MD5,与token参数比对
如果token比对失败返回状态码 500
?
[java] view plain copy?
?
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配置中加入
[html] view plain copy?
?
?
? ? ?
? ? ? ? ?
? ? ? ? ?
? ?
?
?
?
?
?
客户端:
拼接请求接口的所有参数,最后拼接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函数
[html] view plain copy?
?
?
?
?
? ? ?
? ? API test_AG官网亚游 ?
? ? ?
? ? ?
? ? ?
? ? ?
?
?
??
? ?
?
? ? ? ?
Search:
?
? ? ? ? token_key ?
? ? ? ? md5 {{md5(str)}} ?
? ? ? ?
?
? ? ? ?
?
? ? ? ?
?
? ? ? ? ? ?
?
? ? ? ? ? ? ?
? ? ? ? ? ? {{api.request(api.params, value0, value1, value2, value3, value4, value5, value6, value7, value8, value9)}} ?
? ? ? ? ? ?
?
? ? ? ? ? ?
?
? ? ? ? ? ? {{concat(value0, value1, value2, value3, value4, value5, value6, value7, value8, value9)}} ?
? ? ? ? ? ?
?
? ? ? ? ? ? {{api.params[0]}} ?
? ? ? ? ? ? {{api.params[1]}} ?
? ? ? ? ? ? {{api.params[2]}} ?
? ? ? ? ? ? {{api.params[3]}} ?
? ? ? ? ? ? {{api.params[4]}} ?
? ? ? ? ? ? {{api.params[5]}} ?
? ? ? ? ? ? {{api.params[6]}} ?
? ? ? ? ? ? {{api.params[7]}} ?
? ? ? ? ? ? {{api.params[8]}} ?
? ? ? ? ? ? {{api.params[9]}} ?
? ? ? ? ? ? token ?
? ? ? ? ? ? ?
? ? ? ? ? ?
?
? ? ? ? ? ?
?
? ? ? ?
?
? ?
?
??
?
?
免费开发基础+项目实战班,火爆抢座中... (前50名享19元住宿)

就业保障

申请优惠

免费试学

立即报名

在线咨询

视频教程