特别提示:本人博客部分有参考网络其他博客,但均是本人亲手编写过并验证通过。如发现博客有错误,请及时提出以免误导其他人,谢谢!欢迎转载,但记得标明文章出处:http://www.cnblogs.com/mao2080/

设计思路

主要针对需要登录后操作的接口进行校验。接入层在对外暴露接口后,网页、APP、第三方等等途径进行访问接口。用户请求首先会被SpringMVC拦截器拦截到,在拦截器里第一步就是需要校验用户的登录身份(由于是分布式系统这里采用的是userId+accessToken方式来校验),登录校验通过之后再进行用户权限校验,此时会自动拦截@AuthValidate注解的method(核心),如果权限校验失败则抛出权限不足异常,否则校验通过之后再执行具体接口并返回结果。

1、自定义注解

 package com.mao.auth;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; /**
*
* 项目名称:---
* 模块名称:接入层
* 功能描述:权限定义
* 创建人: mao2080@sina.com
* 创建时间:2017年5月9日 下午8:41:05
* 修改人: mao2080@sina.com
* 修改时间:2017年5月9日 下午8:41:05
*/
@Target(value = ElementType.METHOD)
@Retention(value = RetentionPolicy.RUNTIME)
@Documented
public @interface AuthValidate { /**
*
* 描述:权限定义
* @author mao2080@sina.com
* @created 2017年5月8日 上午11:36:41
* @since
* @return 权限代码
*/
AuthCode value() default AuthCode.Allow; }

2、权限枚举

 package com.mao.auth;

 /**
*
* 项目名称:---
* 模块名称:接入层
* 功能描述:权限类型枚举
* 创建人: mao2080@sina.com
* 创建时间:2017年5月8日 上午11:43:12
* 修改人: mao2080@sina.com
* 修改时间:2017年5月8日 上午11:43:12
*/
public enum AuthCode { Allow("00000", "00000", "允许访问"), /******************客户权限******************/ AU0001("100001", "AU0001", "新增用户", "新增用户"), AU0002("100002", "AU0002", "删除用户", "批量删除用户"); /**权限标识 */
private String authId; /**权限编码 */
private String authCode; /**权限名称 */
private String authName; /**权限描述 */
private String authDesc; /**
*
* 描述:构建设备类型
* @author mao2080@sina.com
* @created 2017年3月22日 上午13:50:58
* @since
* @param authId 权限标识
* @param authCode 权限编码
* @param authName 权限名称
* @return
*/
private AuthCode(String authId, String authCode, String authName) {
this.authId = authId;
this.authCode = authCode;
this.authName = authName;
} /**
*
* 描述:构建设备类型
* @author mao2080@sina.com
* @created 2017年3月22日 上午13:50:58
* @since
* @param authId 权限标识
* @param authCode 权限编码
* @param authName 权限名称
* @param authDesc 权限描述
* @return
*/
private AuthCode(String authId, String authCode, String authName, String authDesc) {
this.authId = authId;
this.authCode = authCode;
this.authName = authName;
this.authDesc = authDesc;
} public String getAuthId() {
return authId;
} public void setAuthId(String authId) {
this.authId = authId;
} public String getAuthCode() {
return authCode;
} public void setAuthCode(String authCode) {
this.authCode = authCode;
} public String getAuthDesc() {
return authDesc;
} public void setAuthDesc(String authDesc) {
this.authDesc = authDesc;
} public String getAuthName() {
return authName;
} public void setAuthName(String authName) {
this.authName = authName;
} @Override
public String toString() {
return String.format("authId:%s, authCode:%s, authName:%s, authDesc:%s", this.authId, this.authCode, this.authName, this.authDesc);
} }

3、Controller使用自定义注解

 package com.mao.controller;

 import javax.servlet.http.HttpServletRequest;

 import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody; import com.mao.auth.AuthCode;
import com.mao.auth.AuthValidate;
import com.mao.beans.ResObject;
import com.mao.exception.BusinessException; /**
*
* 项目名称:---
* 模块名称:接入层
* 功能描述:用户控制层
* 创建人: mao2080@sina.com
* 创建时间:2017年5月9日 下午8:15:50
* 修改人: mao2080@sina.com
* 修改时间:2017年5月9日 下午8:15:50
*/
@Controller
@RequestMapping("/userController")
public class UserController { /**日志*/
@SuppressWarnings("unused")
private static final Log loger = LogFactory.getLog(UserController.class); /**
*
* 描述:新增用户
* @author mao2080@sina.com
* @created 2017年5月9日 下午8:16:41
* @since
* @param request
* @return
* @throws BusinessException
*/
@RequestMapping("/createUser")
@ResponseBody
@AuthValidate(AuthCode.AU0001)
public ResObject createUser(HttpServletRequest request) throws BusinessException{
//业务代码
return new ResObject();
} /**
*
* 描述:新增用户
* @author mao2080@sina.com
* @created 2017年5月9日 下午8:16:41
* @since
* @param request
* @return
* @throws BusinessException
*/
@RequestMapping("/deleteUser")
@ResponseBody
@AuthValidate(AuthCode.AU0002)
public ResObject deleteUser(HttpServletRequest request) throws BusinessException{
//业务代码
return new ResObject();
}
}

4、SpringMVC拦截器

 package com.mao.interceptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView; import com.mao.auth.AuthCode;
import com.mao.auth.AuthValidate;
import com.mao.exception.BusinessException;
import com.mao.util.JsonUtil; /**
*
* 项目名称:---
* 模块名称:接入层
* 功能描述:用户登录拦截器(利用SpringMVC自定义拦截器实现)
* 创建人: mao2080@sina.com
* 创建时间:2017年4月25日 下午8:53:49
* 修改人: mao2080@sina.com
* 修改时间:2017年4月25日 下午8:53:49
*/
public class UserLoginInterceptor implements HandlerInterceptor { /**
*
* 描述:构造函数
* @author mao2080@sina.com
* @created 2017年4月28日 下午5:20:34
* @since
* @param accessService
*/
public UserLoginInterceptor() { } /**
*
* 描述:执行方法前
* @author mao2080@sina.com
* @created 2017年4月25日 下午9:01:44
* @since
* @param request HttpServletRequest
* @param response HttpServletResponse
* @param handler handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
try {
//校验登录
this.userLoginValidate(request);
//校验权限
this.userAuthValidate(request, handler);
} catch (Exception e) {
e.printStackTrace();
printMessage(response, e);
return false;
}
return true;
} /**
*
* 描述:输出到前端
* @author mao2080@sina.com
* @created 2017年4月28日 上午11:00:25
* @since
* @param response 响应
* @param res 对象
* @throws Exception
*/
public static void printMessage(HttpServletResponse response, Object res) throws Exception{
PrintWriter writer = null;
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset=utf-8");
try {
writer = response.getWriter();
writer.print(JsonUtil.toJson(res));
} catch (Exception e) {
e.printStackTrace();
} finally {
if (writer != null){
writer.close();
}
}
} @Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } /**
*
* 描述:用户登录校验
* @author mao2080@sina.com
* @created 2017年5月9日 下午8:27:25
* @since
* @param request
* @throws BusinessException
*/
private void userLoginValidate(HttpServletRequest request) throws BusinessException {
//校验代码
} /**
*
* 描述:用户权限校验
* @author mao2080@sina.com
* @created 2017年5月4日 下午8:34:09
* @since
* @param request HttpServletRequest
* @param handler
* @return
* @throws BusinessException
*/
private void userAuthValidate(HttpServletRequest request, Object handler) throws BusinessException {
AuthValidate validate = ((HandlerMethod) handler).getMethodAnnotation(AuthValidate.class);
if(validate == null){
throw new BusinessException("未配置自定义注解");
}
String funcCode = validate.value().getAuthCode();
if(funcCode.equals(AuthCode.Allow.getAuthCode())){
return;
}
String authId = validate.value().getAuthId();
List<String> auths = new ArrayList<>();//模拟从缓存或者从数据库中查询出对应用户的权限
if(!auths.contains(authId)){
throw new BusinessException("权限不足");
}
} }

5、拦截器配置

 package com.mao.interceptor;

 import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; /**
*
* 项目名称:---
* 模块名称:接入层
* 功能描述:拦截器配置
* 创建人: mao2080@sina.com
* 创建时间:2017年5月9日 下午8:54:00
* 修改人: mao2080@sina.com
* 修改时间:2017年5月9日 下午8:54:00
*/
@Configuration
@ComponentScan(basePackages={"com.mao"})
@EnableWebMvc
public class WebConfiguration extends WebMvcConfigurerAdapter { /**日志*/
private static final Log loger = LogFactory.getLog(WebConfiguration.class); /**
*
* 描述:构造函数
* @author mao2080@sina.com
* @created 2017年5月3日 下午4:48:41
* @since
*/
public WebConfiguration() {
loger.info("开启系统登录拦截");
} /**
*
* 描述:添加拦截器
* @author mao2080@sina.com
* @created 2017年4月25日 下午8:50:54
* @since
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
this.excludeUserLogin(registry.addInterceptor(new UserLoginInterceptor()));
} /**
*
* 描述:拦截请求
* @author mao2080@sina.com
* @created 2017年5月9日 下午8:55:28
* @since
* @param registration
*/
public void excludeUserLogin(InterceptorRegistration registration){
registration.addPathPatterns("/userController/*");
} }

6、返回对象

 package com.mao.beans;

 import java.io.Serializable;

 /**
*
* 项目名称:
* 模块名称:
* 功能描述:
* 创建人: mao2080@sina.com
* 创建时间:2017年5月3日 下午6:37:11
* 修改人: mao2080@sina.com
* 修改时间:2017年5月3日 下午6:37:11
*/
public class ResObject implements Serializable{ /**序列号*/
private static final long serialVersionUID = 589903502110209046L; /**返回代码*/
private int code = 200; /**返回信息*/
private String desc = "Success."; /**返回数据*/
private Object data; /**
*
* 构建函数
* @author mao2080@sina.com
* @created 2017年3月24日 下午4:25:23
* @since
*/
public ResObject() { } /**
*
* 描述:构造函数
* @author mao2080@sina.com
* @created 2017年4月18日 下午3:32:26
* @since
* @param data 数据
*/
public ResObject(Object data) {
super();
this.data = data;
} /**
*
* 构建函数
* @author mao2080@sina.com
* @created 2017年3月24日 下午4:25:35
* @since
* @param code 返回代码
* @param desc 返回信息
*/
public ResObject(int code, String desc) {
super();
this.code = code;
this.desc = desc;
} /**
*
* 构建函数
* @author mao2080@sina.com
* @created 2017年3月24日 下午4:25:39
* @since
* @param code 返回代码
* @param desc 返回信息
* @param data 返回数据
*/
public ResObject(int code, String desc, Object data) {
super();
this.code = code;
this.desc = desc;
this.data = data;
} public Object getData() {
return data;
} public void setData(Object data) {
this.data = data;
} public int getCode() {
return code;
} public void setCode(int code) {
this.code = code;
} public String getDesc() {
return desc;
} public void setDesc(String desc) {
this.desc = desc;
} }

ResObject

7、异常类

 package com.mao.exception;

 /**
*
* 项目名称:---
* 模块名称:接入层
* 功能描述:异常类
* 创建人: mao2080@sina.com
* 创建时间:2017年5月9日 下午8:22:21
* 修改人: mao2080@sina.com
* 修改时间:2017年5月9日 下午8:22:21
*/
public class BusinessException extends Exception{ public BusinessException() { } public BusinessException(String message) {
super(message);
} }

BusinessException

8、json工具类

 package com.mao.util;

 import com.alibaba.dubbo.common.utils.StringUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.mao.exception.BusinessException; /**
*
* 项目名称:---
* 模块名称:常用工具类
* 功能描述:json工具类
* 创建人: mao2080@sina.com
* 创建时间:2017年3月28日 上午11:56:15
* 修改人: mao2080@sina.com
* 修改时间:2017年3月28日 上午11:56:15
*/
public class JsonUtil { /**
*
* 描述:将对象格式化成json字符串
* @author mao2080@sina.com
* @created 2017年4月1日 下午4:38:18
* @since
* @param object 对象
* @return json字符串
* @throws BusinessException
*/
public static String toJson(Object object) throws BusinessException {
try {
return JSON.toJSONString(object, new SerializerFeature[] {
SerializerFeature.WriteMapNullValue,
SerializerFeature.DisableCircularReferenceDetect,
SerializerFeature.WriteNonStringKeyAsString });
} catch (Exception e) {
throw new BusinessException();
}
} /**
*
* 描述:将对象格式化成json字符串(PrettyFormat格式)
* @author mao2080@sina.com
* @created 2017年4月1日 下午4:38:18
* @since
* @param object 对象
* @return json字符串
* @throws BusinessException
*/
public static String toJsonFormat(Object object) throws BusinessException {
try {
return JSON.toJSONString(object, new SerializerFeature[] {
SerializerFeature.WriteMapNullValue,
SerializerFeature.PrettyFormat,
SerializerFeature.DisableCircularReferenceDetect,
SerializerFeature.WriteNonStringKeyAsString });
} catch (Exception e) {
throw new BusinessException();
}
} /**
*
* 描述:转Map
* @author mao2080@sina.com
* @created 2017年4月1日 下午5:00:20
* @since
* @param obj 对象
* @return object
* @throws BusinessException
*/
public static Object toJsonObject(Object obj) throws BusinessException {
try {
return JSON.toJSON(obj);
} catch (Exception e) {
throw new BusinessException();
}
} /**
*
* 描述:将json串转为对象
* @author mao2080@sina.com
* @created 2017年4月1日 下午5:01:23
* @since
* @param jsonString json串
* @param clazz 对象
* @return
* @throws BusinessException
*/
public static <T> T fromJson(String jsonString, Class<T> clazz) throws BusinessException {
try {
if (StringUtils.isBlank(jsonString)) {
return null;
}
return (T) JSON.parseObject(jsonString, clazz);
} catch (Exception e) {
throw new BusinessException();
}
} /**
*
* 描述:暂时不开通
* @author mao2080@sina.com
* @created 2017年4月1日 下午5:08:12
* @since
* @param jsonString
* @return
* @throws Exception
*/
@SuppressWarnings("unused")
private static <T> T fromJson(String jsonString) throws Exception {
return JSON.parseObject(jsonString, new TypeReference<T>() {
}, new Feature[0]);
} }

JsonUtil

SpringMVC拦截器+Spring自定义注解实现权限验证的更多相关文章

  1. struts2拦截器加自定义注解实现权限控制

    https://blog.csdn.net/paul342/article/details/51436565 今天结合Java的Annotation和Struts2进行注解拦截器权限控制. 功能需求: ...

  2. SpringMVC拦截器2(资源和权限管理)(作为补充说明)

    SpringMVC拦截器(资源和权限管理) 1.DispatcherServlet SpringMVC具有统一的入口DispatcherServlet,所有的请求都通过DispatcherServle ...

  3. SpringMVC(9)实现注解式权限验证

    对大部分系统来说都需要权限管理来决定不同用户可以看到哪些内容,那么如何在Spring MVC中实现权限验证呢?当然我们可以继续使用servlet中的过滤器Filter来实现.但借助于Spring MV ...

  4. Spring MVC基础知识整理➣拦截器和自定义注解

    概述 Spring MVC中通过注解来对方法或者类进行动态的说明或者标注,类似于配置标识文件的属性信息.当标注的类或者方式被使用时候,通过提取注解信息来达到对类的动态处理.在 MVC中,我们常用的注解 ...

  5. [Java]利用拦截器和自定义注解做登录以及权限验证

    1.自定义注解 需要验证登录的注解 package com.etaofinance.wap.common; import java.lang.annotation.Documented; import ...

  6. 拦截器和自定义注解@interface

    1 .拦截器(Interceptor): 用于在某个方法被访问之前进行拦截,然后在Handler执行之前或之后加入某些操作,其实就是AOP的一种实现策略. 拦截用户的请求并进行相应的处理,比如:判断用 ...

  7. SpringBoot 拦截器和自定义注解判断请求是否合法

    应用场景举例: 当不同身份的用户请求一个接口时,用来校验用户某些身份,这样可以对单个字段数据进行精确权限控制,具体看代码注释 自定义注解 /** * 对比请求的用户身份是否符合 * @author l ...

  8. SpringMVC拦截器和@ResponseBody注解冲突

    在使用@ResponseBody注解后controller方法只会返回ModelandView对象的数据模型,不会返回视图,这样有很多好处,但是如果在拦截器中进行了页面转发,在满足页面转发条件时,不会 ...

  9. SpringMVC(10)实现注解式权限验证

    在项目中如何处理出现的异常,在每个可能出现异常的地方都写代码捕捉异常?这显然是不合理的,当项目越来越大是也是不可维护的.那么如何保证我们处理异常的代码精简且便于维护呢?这就是本篇要讲的内容->异 ...

随机推荐

  1. 使用elasticsearch7.3版本在一台主机上部署多个实例组建集群

    系统:centos 7.4 x64 主机ip:192.168.0.160 软件包:elasticsearch-7.3.0-linux-x86_64.tar.gz 配置步骤 vim /etc/secur ...

  2. [.net core]9.中间件的具体实现

    查看Startup.cs的configure方法 public void Configure(IApplicationBuilder app, IHostingEnvironment env) { i ...

  3. Oracle及SQLPLUS使用笔记

    Oracle及SQLPLUS使用笔记 自己之前粗粗的学过MySQL,学校用的是Oracle,学生使用sqlplus,这是个命令行界面的数据库管理软件(为了学习嘛,不用图形化可以理解),这里记录一些使用 ...

  4. vue与react对比

    相同点 1.都使用 virtual DOM 2.都是组件化开发 or 都提供了组件化的视图组件 3.数据的改变会引起视图的二次渲染 4.都只有骨架,其他的功能如路由.状态管理等是框架分离的组件. 5. ...

  5. 多层 iframe 嵌套 js 方法调用

    一下午一个这破问题,浪费了不少时间,怎么也实现不了我的上上级iframe 刷新.NND. 实现了,记录一下下吧: window.parent.parent.document.getElementByI ...

  6. atxserver2-rethinkdb的一些基础操作

    因为我只需要一些基础操作就好,所以在web端的 Data Explorer 操作,首先启动  rethinkdb.exe,然后登陆网页端, 下面是一些基础操作的语句, 一.创建表r.db(‘atxse ...

  7. linux命令详解——ln

    ln是linux中又一个非常重要命令,它的功能是为某一个文件在另外一个位置建立一个同不的链接,这个命令最常用的参数是-s,具体用法是:ln -s 源文件 目标文件. 当我们需要在不同的目录,用到相同的 ...

  8. 012-zabbix主动模式

    6.1 主动模式 zabbix agent检测分为主动(agent active)和被动(agent)两种形式,主动与被动的说法均是相对于agent来讨论的.简单说明一下主动与被动的区别如下: 主动: ...

  9. Linux日常之命令tee

    命令tee (1)读取标准输入的数据,并将其内容输出成文件 (2)主要用于重定向到文件 常用参数 -a,将读取的内容追加到文件的后面,而不是覆盖(在默认的情况下是覆盖) 命令tee与重定向的区别 重定 ...

  10. 记一次使用dubbo过程中版本冲突导致的坑

    前言:2019年09月23日临下班,产品的一个变更需求临近尾声阶段.本地测试OK,兴致冲冲的想着发布到测试环境,验证一下没有问题,五分钟结束战斗,明天就开始下个需求了.随在CE(公司的devOps系统 ...