zoukankan      html  css  js  c++  java
  • 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/

  • 相关阅读:
    移动应用专项测试
    MAC连接安卓手机通过adb指令安装apk
    Git GUI可视化操作教程
    nestjs中typeorm进行事物操作
    vue-element-admin 实现动态路由(从后台查询出菜单列表绑定侧边栏)
    el-form 表单校验
    vscode设置VUE eslint开发环境
    .netcore signalR 实时消息推送
    psexec局域网执行远程命令
    Asp.Net跨平台 Jexus 5.8.1 独立版
  • 原文地址:https://www.cnblogs.com/magic101/p/7732016.html
Copyright © 2011-2022 走看看