이 글에서는 주로 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] != '') 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>
위 내용은 Java에서 인터페이스 검증을 구현하는 세 가지 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!