利用spring AOP 实现统一校验
开发环境
- 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 实现统一校验的更多相关文章
- 化繁就简,如何利用Spring AOP快速实现系统日志
1.引言 有关Spring AOP的概念就不细讲了,网上这样的文章一大堆,要讲我也不会比别人讲得更好,所以就不啰嗦了. 为什么要用Spring AOP呢?少写代码.专注自身业务逻辑实现(关注本身的业务 ...
- 利用Spring AOP自定义注解解决日志和签名校验
转载:http://www.cnblogs.com/shipengzhi/articles/2716004.html 一.需解决的问题 部分API有签名参数(signature),Passport首先 ...
- (转)利用Spring AOP自定义注解解决日志和签名校验
一.需解决的问题 部分API有签名参数(signature),Passport首先对签名进行校验,校验通过才会执行实现方法. 第一种实现方式(Origin):在需要签名校验的接口里写校验的代码,例如: ...
- 利用spring AOP 和注解实现方法中查cache-我们到底能走多远系列(46)
主题:这份代码是开发中常见的代码,查询数据库某个主表的数据,为了提高性能,做一次缓存,每次调用时先拿缓存数据,有则直接返回,没有才向数据库查数据,降低数据库压力. public Merchant lo ...
- 利用Spring AOP和自定义注解实现日志功能
Spring AOP的主要功能相信大家都知道,日志记录.权限校验等等. 用法就是定义一个切入点(Pointcut),定义一个通知(Advice),然后设置通知在该切入点上执行的方式(前置.后置.环绕等 ...
- 利用Spring AOP切面对用户访问进行监控
开发系统时往往需要考虑记录用户访问系统查询了那些数据.进行了什么操作,尤其是访问重要的数据和执行重要的操作的时候将数记录下来尤显的有意义.有了这些用户行为数据,事后可以以用户为条件对用户在系统的访问和 ...
- Spring AOP实现统一日志输出
目的: 统一日志输出格式 思路: 1.针对不同的调用场景定义不同的注解,目前想的是接口层和服务层. 2.我设想的接口层和服务层的区别在于: (1)接口层可以打印客户端IP,而服务层不需要 (2)接口层 ...
- 利用Spring AOP机制拦截方法一例
直接上代码: @Aspect // for aop @Component // for auto scan @Order(0) // execute before @Transactional pub ...
- 利用spring AOP实现每个请求的日志输出
前提条件: 除了spring相关jar包外,还需要引入aspectj包. <dependency> <groupId>org.aspectj</groupId> & ...
随机推荐
- 一种实现C++反射功能的想法(三)
如何实现类型名跟类型的对应, 我们很容易想到map, 没错, 就是使用map实现的. std::map<std::string, .....>, 等下, 第二部分该填什么类型, 一个函数指 ...
- 【vc】1_Windows程序内部运行机制
创建一个Win32应用程序步骤: 1.编写WinMain函数; 2.创建窗口(步骤如下): a.设计(一个)窗口类(WNDCLASS) b.注册(该)窗口类. c.创建窗口. d.显示并更新窗口. 3 ...
- javascript DOM艺术
一.DOM基础1.节点(node)层次Document--最顶层的节点,所有的其他节点都是附属于它的.DocumentType--DTD引用(使用<!DOCTYPE>语法)的对象表现形式, ...
- 使用Thinkphp框架开发移动端接口
本文给大家分享的是使用thinkphp框架开发移动端接口的2种方法,一种是开发API,另外一种是实现移动端访问自动切换移动主题模板,从而实现伪app访问,下面我们就来详细看下如何实现吧. 方案一:给 ...
- 原生Js获取某个节点后面的第一个标签
nextSlbling属性 获取某个节点后面的第一个节点(可能是标签 文本) 判断获取的节点是否为标签节点还是文本节点 window.onload=function(){ var pagecount= ...
- Android Framework------之Keyguard 简单分析
前面对于MediaPlayer的系统研究,刚刚开始,由于其他原因现在要先暂停一下.这次要看的模块是android 4.2 系统中的Keyguard模块.在接触之后才发现,android4.2的keyg ...
- TatukGIS-TGIS_LayerVector-LocateEx
方法原型: function LocateEx(const _ptg: TGIS_Point; const _prec: Double; const _uid: Integer; var _dist: ...
- python连接mysql之pymysql模块
以下demo均以python2中的mysqldb模块 一.插入数据 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import MySQLdb conn = MyS ...
- Python Tutorial 学习(六)--Modules
6. Modules 当你退出Python的shell模式然后又重新进入的时候,之前定义的变量,函数等都会没有了. 因此, 推荐的做法是将这些东西写入文件,并在适当的时候调用获取他们. 这就是为人所知 ...
- uboot总结:uboot配置和启动过程3(config.mk分析)
说明:文件位置:在uboot的目录下,文件名为:config.mk.是一个makefile文件,以后会被主Makefile调用. 它的主要作用的是: (1)具体的设置交叉编译工具链接(主Makefil ...