spring AOP 和自定义注解进行身份验证

一个SSH的项目(springmvc+hibernate),需要提供接口给app使用。首先考虑的就是权限问题,app要遵循极简模式,部分内容无需验证,用过滤器不能解决某些无需验证的方法 所以最终选择用AOP 解决。大致思路是使用自定义注解,在需要权限控制的方法前(controller层)使用注解然后使用AOP拦截访问的方法,判断当前用户是否登录了(判断是否携带了登录之后获取到的 token ),从而决定是否拦截。

开启切面代理

    <!--aop配置,基于类的代理 -->
    <!-- <aop:aspectj-autoproxy  proxy-target-class="true"/>-->
    <aop:aspectj-autoproxy/>

注意:1、一定要放在spring的配置文件中,不要单独新建一个文件

         2、proxy-target-class属性值决定是基于接口的还是基于类的代理被创建。如果proxy-target-class 属性值被设置为true,那么基于类的代理将起作用(这时需要cglib库)。如果proxy-target-class属值被设置为false或者这个属性被省略,那么标准的JDK 基于接口的代理将起作用。

编写一个自定义注解

@Retention(RetentionPolicy.RUNTIME)//注解会在class中存在,运行时可通过反射获取    
@Target(ElementType.METHOD)//目标是方法  
@Documented
public @interface LoginRequired{

}

ElementType.MeTHOD 表示该自定义注解可以用在方法上
RetentionPolicy.RUNTIME 表示该注解在代码运行时起作用

可以在自定义注解中加入一些默认方法

定义切面类验证权限

@Component
@Aspect
public class TokenInterceptor {

    private static final Logger logger = Logger.getLogger(TokenInterceptor.class);

    @Resource
    private BllUserService bllUserService;

    @Pointcut("@annotation(org.jeecgframework.core.annotation.LoginRequired)")  
    public  void serviceAspect() {  
    }  
//环绕通知(特别适合做权限系统)
//@Before @Around("serviceAspect()") public Object checkPermission(ProceedingJoinPoint joinPoint) throws Throwable{ AjaxJson json=new AjaxJson(); // String methodName = joinPoint.getSignature().getName(); // Object target = joinPoint.getTarget(); // Method method = getMethodByClassAndName(target.getClass(), methodName); //得到拦截的方法 Object[] args = joinPoint.getArgs(); HttpServletRequest request=(HttpServletRequest)args[0]; if(!validate(request)){ //request.setAttribute("message", "您没有执行该操作权限"); json.setMsg("您没有执行该操作权限"); json.setSuccess(false); return json; } return joinPoint.proceed(); } private boolean validate(HttpServletRequest request)throws Exception {
// String token=request.getParameter("token");//根据前端传值进行修改 String token
=request.getHeader("token"); if(StringUtil.isEmpty(token)){ } Map<String, Object> resultMap=Jwt.validToken(token); TokenState state=TokenState.getTokenState((String)resultMap.get("state")); switch (state) { case VALID: //取出payload中数据,放入到request作用域中 request.setAttribute("data", resultMap.get("data")); break; case EXPIRED://暂时没做 case INVALID: return false; } return true; } public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { }

@Aspect放在类头上,把这个类作为一个切面。

@Compenent注解标识其为Spring管理Bean,而@Aspect注解不能被Spring自动识别并注册为Bean,必须通过@Component注解来完成

注:这儿用了JWT做token验证,感兴趣的同学自行百度

TOKEN验证类

   /**
     * 校验token是否合法,返回Map集合,集合中主要包含    state状态码   data鉴权成功后从token中提取的数据
     * 该方法在过滤器中调用,每次请求API时都校验
     * @param token
     * @return  Map<String, Object>
     */
    public static Map<String, Object> validToken(String token) {
        Map<String, Object> resultMap = new HashMap<String, Object>();
        try {
            JWSObject jwsObject = JWSObject.parse(token);
            Payload payload = jwsObject.getPayload();
            JWSVerifier verifier = new MACVerifier(SECRET);

            if (jwsObject.verify(verifier)) {
                JSONObject jsonOBj = payload.toJSONObject();
                // token校验成功(此时没有校验是否过期)
                resultMap.put("state", TokenState.VALID.toString());
                // 若payload包含ext字段,则校验是否过期
                if (jsonOBj.containsKey("ext")) {
                    long extTime = Long.valueOf(jsonOBj.get("ext").toString());
                    long curTime = new Date().getTime();
                    // 过期了
                    if (curTime > extTime) {
                        resultMap.clear();
                        resultMap.put("state", TokenState.EXPIRED.toString());
                    }
                }
                resultMap.put("data", jsonOBj);

            } else {
                // 校验失败
                resultMap.put("state", TokenState.INVALID.toString());
            }

        } catch (Exception e) {
            //e.printStackTrace();
            // token格式不合法导致的异常
            resultMap.clear();
            resultMap.put("state", TokenState.INVALID.toString());
        }
        return resultMap;
    }    

配置拦截器

    @RequestMapping(params = "physicalList")
    @ResponseBody
    @LoginRequired
    public AjaxJson getPhysicalList(HttpServletRequest request){
    
    }

测试

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1, maximum-scale=1">
        <title></title>
    </head>
    <body>
        
        <button type="button"  onclick="getdata()">测试页面</button><br/>
        <script type="text/javascript" src="js/jquery.min.js" ></script>
        <script>
             var token="123";
            function getdata(){
                $.ajax({
                    type:"post",
                    dataType:"json",
                    url:"",
                    headers:{
                        token:token//将token放到请求头中
                    },
        //            beforeSend: function(request) {
         //               request.setRequestHeader("token", token);
          //          },
                    success:function(data){
                        console.log(data);
                        $('body').append(JSON.stringify(data));
                        
                    },
            });
            }
        </script>
    </body>
</html>

可以发现页面请求被拦截了

参考:http://blog.csdn.net/caomiao2006/article/details/51287206

http://www.jianshu.com/p/576dbf44b2ae

http://www.scienjus.com/restful-token-authorization/

原文地址:https://www.cnblogs.com/magic101/p/7732016.html