开发环境

  • JDK: 1.7
  • spring: 4.0.6
  • aspect: 1.7.4

应用背景

  在APP与后台通讯的过程中,我们一般都会有个authToken的字符串校验,判断那些请求是需要校验用户信息的,因为APP用户并不需要登录到我们的后台系统,所以一些基于session的权限控制(比如shiro)并不合适,所以导致我们又回到了解放前,很多请求都需要先校验这个用户的信息,不通过的就重定向到登录界面,比如下面的代码:

    AppUser user = appUserService.getUserByAuthToken(appointmentSearchVo.getAuthToken());
if (null == user) {
throw new BizException(ErrorMessage.CHECK_AUTHTOKEN_FAIL);
}

  可以看到在很多的控制器下都会有这样一段代码,太丑陋了,像这些重复的但又必不可少的操作,用AOP的方式做统一处理是很优雅的,我的思路是:

  • 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;
}

利用spring AOP 实现统一校验的更多相关文章

  1. 化繁就简,如何利用Spring AOP快速实现系统日志

    1.引言 有关Spring AOP的概念就不细讲了,网上这样的文章一大堆,要讲我也不会比别人讲得更好,所以就不啰嗦了. 为什么要用Spring AOP呢?少写代码.专注自身业务逻辑实现(关注本身的业务 ...

  2. 利用Spring AOP自定义注解解决日志和签名校验

    转载:http://www.cnblogs.com/shipengzhi/articles/2716004.html 一.需解决的问题 部分API有签名参数(signature),Passport首先 ...

  3. (转)利用Spring AOP自定义注解解决日志和签名校验

    一.需解决的问题 部分API有签名参数(signature),Passport首先对签名进行校验,校验通过才会执行实现方法. 第一种实现方式(Origin):在需要签名校验的接口里写校验的代码,例如: ...

  4. 利用spring AOP 和注解实现方法中查cache-我们到底能走多远系列(46)

    主题:这份代码是开发中常见的代码,查询数据库某个主表的数据,为了提高性能,做一次缓存,每次调用时先拿缓存数据,有则直接返回,没有才向数据库查数据,降低数据库压力. public Merchant lo ...

  5. 利用Spring AOP和自定义注解实现日志功能

    Spring AOP的主要功能相信大家都知道,日志记录.权限校验等等. 用法就是定义一个切入点(Pointcut),定义一个通知(Advice),然后设置通知在该切入点上执行的方式(前置.后置.环绕等 ...

  6. 利用Spring AOP切面对用户访问进行监控

    开发系统时往往需要考虑记录用户访问系统查询了那些数据.进行了什么操作,尤其是访问重要的数据和执行重要的操作的时候将数记录下来尤显的有意义.有了这些用户行为数据,事后可以以用户为条件对用户在系统的访问和 ...

  7. Spring AOP实现统一日志输出

    目的: 统一日志输出格式 思路: 1.针对不同的调用场景定义不同的注解,目前想的是接口层和服务层. 2.我设想的接口层和服务层的区别在于: (1)接口层可以打印客户端IP,而服务层不需要 (2)接口层 ...

  8. 利用Spring AOP机制拦截方法一例

    直接上代码: @Aspect // for aop @Component // for auto scan @Order(0) // execute before @Transactional pub ...

  9. 利用spring AOP实现每个请求的日志输出

    前提条件: 除了spring相关jar包外,还需要引入aspectj包. <dependency> <groupId>org.aspectj</groupId> & ...

随机推荐

  1. POJ2104 K-th Number 静态区间第k最值 平方分割

    干掉这道题的那一刻,我只想说:我终于**的AC了!!! 最终内存1344K,耗时10282ms,比起归并树.划分树以及其他各种黑科技,这个成绩并不算光彩⊙﹏⊙ 但至少,从最初的无数次TLE到最终的AC ...

  2. cocos2dx ease 公式

    所有ease计算公式都在CCTweenFunction.cpp里.

  3. cmd 命令行下复制、粘贴的快捷键

    1.单击左下角“开始”菜单,选择“运行”,输入“cmd”. 2.在弹出的cmd窗口的标题栏上点击“右键”,选择“属性”. 3.在弹出的对话框中选择“选项”这个选项卡,在“编辑选项”区域中勾选“快速编辑 ...

  4. 『重构--改善既有代码的设计』读书笔记----Move Method

    明确函数所在类的位置是很重要的.这样可以避免你的类与别的类有太多耦合.也会让你的类的内聚性变得更加牢固,让你的整个系统变得更加整洁.简单来说,如果在你的程序中,某个类的函数在使用的过程中,更多的是在和 ...

  5. Android自定义View基础

    自定义控件, 视频教程 http://www.jikexueyuan.com/course/1748.html 1. 编写自定义view 2. 加入逻辑线程 3. 提取和封装自定义view 4. 利用 ...

  6. NodeJs开发学习目录

    1.Nodejs基本概念及Nodejs.npm安装测试[2014-06-06] 2.开发工具简介(主要介绍Sublime Text使用) [2014-06-06] 3.Sublime text插件安装 ...

  7. IOS--UISlider的使用方法

    IOS--UISlider的使用方法 // UISlider的常用方法 UISlider *oneSlider = [[UISlider alloc] init]; // 最常用 oneSlider. ...

  8. awk里的各种坑

    今天又遇到一个,一旦需要定义一个局部数组(awk通过把局部变量定义在函数参数列表来实现局部这一特征)那么这个数组可以正常的操作,但是无法对他取长度,一旦使用length(tempArr)会得到这么一个 ...

  9. C# IOCP服务器

    C# IOCP服务器 @by  群63438968 这是我写的unity 网络斗地主的服务器源码,本来我想只公开部份服务端代码的,但是为了回报大家的热情,以及曾经和现在的好兄弟,我计划慢慢开源! 告诉 ...

  10. All in All

    Crawling in process... Crawling failed Description You have devised a new encryption technique which ...