广元企业网站建设,品牌推广策划营销策划,深圳建站模板,徐州cms模板建站文章目录接口校验#xff0c;权限拦截通过自定义注解#xff0c;基于面向切面编程来实现1. 自定义异常2. 自定义注解3. AOP面向切面类4. Controller层使用统一异常处理和信息返回1. 创建统一信息返回类2. 创建全局统一异常处理类3. 创建一个枚举类型4. 创建自定义的异常类拦截…文章目录接口校验权限拦截通过自定义注解基于面向切面编程来实现1. 自定义异常2. 自定义注解3. AOP面向切面类4. Controller层使用统一异常处理和信息返回1. 创建统一信息返回类2. 创建全局统一异常处理类3. 创建一个枚举类型4. 创建自定义的异常类拦截器JWT实现登录校验1. 添加依赖2. JWT工具包3. Threadlocal保存用户信息4. 拦截器校验登录5. 注册拦截器6. 自定义注解AOP角色校验7. Controller层示例接口校验权限拦截通过自定义注解基于面向切面编程来实现加依赖dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-aop/artifactId/dependencydependencygroupIdcom.google.guava/groupIdartifactIdguava/artifactIdversion29.0-jre/version/dependency1. 自定义异常// com.yourpackage.exception.AccessDeniedException.java package com.yourpackage.exception;publicclassAccessDeniedExceptionextendsRuntimeException{publicAccessDeniedException(Stringmessage){super(message);}}继承RuntimeException是为了让他必须是非受检异常不需要再方法上显示throws2. 自定义注解//Target(ElementType.METHOD)Retention(RetentionPolicy.RUNTIME)publicinterfacehasRole{String[]value();//允许的用户类型数组}元注解作用Target指定注解可用的位置(如方法、类、字段等)Retention指定注解保留策略(源码/编译器/运行时)Documented是否包含在JavaDoc中Inherited子类是否继承父类的注解3. AOP面向切面类AspectComponentpublicclassRoleCheckAspect{Around(annotation(hasRole))publicObjectcheckPermission(ProceedingJoinPointjoinPoint,HasRolehasRole)throwsThrowable{// 1. 从 session 获取当前用户WhitelistSettingcurrentUserSessionUtils.getCurrentUserInfo();if(currentUsernull){thrownewRuntimeException(用户未登录请先登录);}// 2. 获取用户的角色ID假设 WhitelistSetting 有 getRoleId() 方法StringuserRoleIdcurrentUser.getRoleId();if(userRoleIdnull||userRoleId.trim().isEmpty()){thrownewRuntimeException(用户角色信息缺失);}// 3. 获取注解中允许的角色列表String[]allowedRoleshasRole.value();if(allowedRolesnull||allowedRoles.length0){thrownewRuntimeException(HasRole 注解必须指定至少一个角色);}// 4. 校验用户角色是否在允许列表中booleanhasAccessArrays.asList(allowedRoles).contains(userRoleId);if(!hasAccess){thrownewRuntimeException(权限不足需要角色 [String.join(, ,allowedRoles)]当前角色为 [userRoleId]);}// 5. 放行returnjoinPoint.proceed();}}4. Controller层使用RestControllerRequestMapping(/api)publicclassDemoController{GetMapping(/admin/data)HasRole({ADMIN,SUPER_ADMIN})publicStringadminData(){return管理员专属数据;}GetMapping(/user/profile)HasRole({USER,ADMIN})publicStringuserProfile(){return用户或管理员可访问;}}统一异常处理和信息返回1. 创建统一信息返回类publicclassRespT{//服务端返回的错误码privateintcode200;//服务端返回的错误信息privateStringmsgsuccess;//我们服务端返回的数据privateTdata;privateResp(intcode,Stringmsg,Tdata){this.codecode;this.msgmsg;this.datadata;}publicstaticTRespsuccess(Tdata){ResprespnewResp(200,success,data);returnresp;}publicstaticTRespsuccess(Stringmsg,Tdata){ResprespnewResp(200,msg,data);returnresp;}publicstaticTResperror(AppExceptionCodeMsgappExceptionCodeMsg){ResprespnewResp(appExceptionCodeMsg.getCode(),appExceptionCodeMsg.getMsg(),null);returnresp;}publicstaticTResperror(intcode,Stringmsg){ResprespnewResp(code,msg,null);returnresp;}publicintgetCode(){returncode;}publicStringgetMsg(){returnmsg;}publicTgetData(){returndata;}}2. 创建全局统一异常处理类ControllerAdvicepublicclassGlobalExceptionHandler{ExceptionHandler(value{Exception.class})ResponseBodypublicTRespTexceptionHandler(Exceptione){//这里先判断拦截到的Exception是不是我们自定义的异常类型if(einstanceofAppException){AppExceptionappException(AppException)e;returnResp.error(appException.getCode(),appException.getMsg());}//如果拦截的异常不是我们自定义的异常(例如数据库主键冲突)returnResp.error(500,服务器端异常);}}3. 创建一个枚举类型//这个枚举类中定义的都是跟业务有关的异常publicenumAppExceptionCodeMsg{INVALID_CODE(10000,验证码无效),USERNAME_NOT_EXISTS(10001,用户名不存在),USER_CREDIT_NOT_ENOUTH(10002,用户积分不足);;privateintcode;privateStringmsg;publicintgetCode(){returncode;}publicStringgetMsg(){returnmsg;}AppExceptionCodeMsg(intcode,Stringmsg){this.codecode;this.msgmsg;}}4. 创建自定义的异常类publicclassAppExceptionextendsRuntimeException{privateintcode500;privateStringmsg服务器异常;publicAppException(AppExceptionCodeMsgappExceptionCodeMsg){super();this.codeappExceptionCodeMsg.getCode();this.msgappExceptionCodeMsg.getMsg();}publicAppException(intcode,Stringmsg){super();this.codecode;this.msgmsg;}publicintgetCode(){returncode;}publicStringgetMsg(){returnmsg;}}拦截器JWT实现登录校验1. 添加依赖dependencies!-- JWT --dependencygroupIdio.jsonwebtoken/groupIdartifactIdjjwt-api/artifactIdversion0.11.5/version/dependencydependencygroupIdio.jsonwebtoken/groupIdartifactIdjjwt-impl/artifactIdversion0.11.5/versionscoperuntime/scope/dependencydependencygroupIdio.jsonwebtoken/groupIdartifactIdjjwt-jackson/artifactIdversion0.11.5/versionscoperuntime/scope/dependency!-- Spring AOP --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-aop/artifactId/dependency!-- Web --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency/dependencies2. JWT工具包packagecom.demo.util;importio.jsonwebtoken.*;importio.jsonwebtoken.security.Keys;importjavax.crypto.SecretKey;importjava.util.Date;importjava.util.HashMap;importjava.util.Map;publicclassJwtUtils{privatestaticfinallongEXPIRE2*60*60*1000;privatestaticfinalSecretKeySECRET_KEYKeys.hmacShaKeyFor(abcdefg1234567890abcdefg1234567890.getBytes());publicstaticStringgenerateToken(LonguserId,Stringrole){MapString,ObjectclaimsnewHashMap();claims.put(role,role);returnJwts.builder().setClaims(claims).setSubject(String.valueOf(userId)).setExpiration(newDate(System.currentTimeMillis()EXPIRE)).signWith(SECRET_KEY).compact();}publicstaticClaimsparseToken(Stringtoken){returnJwts.parserBuilder().setSigningKey(SECRET_KEY).build().parseClaimsJws(token).getBody();}}3. Threadlocal保存用户信息publicclassUserContext{privatestaticfinalThreadLocalLonguserIdHoldernewThreadLocal();privatestaticfinalThreadLocalStringroleHoldernewThreadLocal();publicstaticvoidsetUserId(Longid){userIdHolder.set(id);}publicstaticLonggetUserId(){returnuserIdHolder.get();}publicstaticvoidsetRole(Stringrole){roleHolder.set(role);}publicstaticStringgetRole(){returnroleHolder.get();}publicstaticvoidclear(){userIdHolder.remove();roleHolder.remove();}}4. 拦截器校验登录importorg.springframework.stereotype.Component;importorg.springframework.web.servlet.HandlerInterceptor;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importcom.fasterxml.jackson.databind.ObjectMapper;ComponentpublicclassAuthInterceptorimplementsHandlerInterceptor{OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{Stringurirequest.getRequestURI();if(uri.equals(/login))returntrue;// 放行登录Stringtokenrequest.getHeader(Authorization);if(tokennull)returnJson(response,401,未登录);else{try{tokentoken.replace(Bearer ,);varclaimsJwtUtils.parseToken(token);UserContext.setUserId(Long.valueOf(claims.getSubject()));UserContext.setRole((String)claims.get(role));returntrue;}catch(Exceptione){returnJson(response,401,Token 无效或过期);returnfalse;}}returnfalse;}privatevoidreturnJson(HttpServletResponseresponse,intcode,Stringmsg)throwsException{response.setContentType(application/json;charsetUTF-8);ObjectMappermappernewObjectMapper();response.getWriter().write(mapper.writeValueAsString(Result.fail(code,msg)));}OverridepublicvoidafterCompletion(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,Exceptionex){UserContext.clear();}}5. 注册拦截器importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.servlet.config.annotation.InterceptorRegistry;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;ConfigurationpublicclassWebConfigimplementsWebMvcConfigurer{AutowiredprivateAuthInterceptorauthInterceptor;OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){registry.addInterceptor(authInterceptor).addPathPatterns(/**);}}6. 自定义注解AOP角色校验importjava.lang.annotation.*;Target(ElementType.METHOD)Retention(RetentionPolicy.RUNTIME)publicinterfaceRequireRole{String[]value();}importorg.aspectj.lang.annotation.*;importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.reflect.MethodSignature;importorg.springframework.stereotype.Component;AspectComponentpublicclassRoleAspect{Around(annotation(RequireRole))publicObjectcheckRole(ProceedingJoinPointjoinPoint)throwsThrowable{MethodSignaturesignature(MethodSignature)joinPoint.getSignature();RequireRoleannotationsignature.getMethod().getAnnotation(RequireRole.class);StringuserRoleUserContext.getRole();for(Stringrole:annotation.value()){if(role.equals(userRole))returnjoinPoint.proceed();}returnResult.fail(403,权限不足);}}7. Controller层示例importorg.springframework.web.bind.annotation.*;importjava.util.Map;RestControllerpublicclassUserController{PostMapping(/login)publicResultMapString,Objectlogin(RequestParamStringusername,RequestParamStringpassword){// 模拟验证LonguserId1L;Stringroleswitch(username){casestudent-student;casecounselor-counselor;caseteacher-teacher;default-student;};StringtokenJwtUtils.createToken(userId,role);MapString,ObjectdataMap.of(token,token,role,role);returnResult.success(data);}RequireRole({student})GetMapping(/list)publicResultStringlist(){returnResult.success(学生可以访问列表);}RequireRole({counselor,teacher})PostMapping(/update)publicResultStringupdate(){returnResult.success(辅导员/老师可以更新);}}