这篇文章主要介绍了浅谈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> <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>
Atas ialah kandungan terperinci Java实现接口校验的三种方式. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Artikel ini membincangkan menggunakan Maven dan Gradle untuk Pengurusan Projek Java, membina automasi, dan resolusi pergantungan, membandingkan pendekatan dan strategi pengoptimuman mereka.

Artikel ini membincangkan membuat dan menggunakan perpustakaan Java tersuai (fail balang) dengan pengurusan versi dan pergantungan yang betul, menggunakan alat seperti Maven dan Gradle.

Artikel ini membincangkan pelaksanaan caching pelbagai peringkat di Java menggunakan kafein dan cache jambu untuk meningkatkan prestasi aplikasi. Ia meliputi persediaan, integrasi, dan faedah prestasi, bersama -sama dengan Pengurusan Dasar Konfigurasi dan Pengusiran PRA Terbaik

Artikel ini membincangkan menggunakan JPA untuk pemetaan objek-relasi dengan ciri-ciri canggih seperti caching dan pemuatan malas. Ia meliputi persediaan, pemetaan entiti, dan amalan terbaik untuk mengoptimumkan prestasi sambil menonjolkan potensi perangkap. [159 aksara]

Kelas kelas Java melibatkan pemuatan, menghubungkan, dan memulakan kelas menggunakan sistem hierarki dengan bootstrap, lanjutan, dan pemuat kelas aplikasi. Model delegasi induk memastikan kelas teras dimuatkan dahulu, yang mempengaruhi LOA kelas tersuai


Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

MantisBT
Mantis ialah alat pengesan kecacatan berasaskan web yang mudah digunakan yang direka untuk membantu dalam pengesanan kecacatan produk. Ia memerlukan PHP, MySQL dan pelayan web. Lihat perkhidmatan demo dan pengehosan kami.

Penyesuai Pelayan SAP NetWeaver untuk Eclipse
Integrasikan Eclipse dengan pelayan aplikasi SAP NetWeaver.

VSCode Windows 64-bit Muat Turun
Editor IDE percuma dan berkuasa yang dilancarkan oleh Microsoft

SublimeText3 versi Inggeris
Disyorkan: Versi Win, menyokong gesaan kod!

ZendStudio 13.5.1 Mac
Persekitaran pembangunan bersepadu PHP yang berkuasa