当前位置:网站首页>两种Controller层接口鉴权方式
两种Controller层接口鉴权方式
2022-06-29 17:38:00 【llp1110】
两种Controller层接口鉴权方式
最近在做一个即时通讯服务时,要求对每个接口的入参进行鉴权处理,这里我整理出来了两种方式:1.基于注解和拦截器鉴权 2.基于注解和AOP鉴权
这里我在采用的是aop的方式,拦截器这里只完成了伪代码进行作为记录。
1.基于注解和拦截器鉴权
拦截器的方式主要需要解决requestBody重复获取的问题
1.首先我们需要定义一个鉴权标识的注解
/** * 鉴权标记注解 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface Authorization {
}
2.重写HttpServletRequestWrapper
通过自定义的HttpServletRequestWrapper 备份一下流的数据,自定义HttpServletRequestWrapper 调用父类request.getInputStream()读取全部数据出来保存在一个byte数组内,当再次获取流数据的时候,自定义的HttpServletRequestWrapper 就会用byte数组重新生成一个新的流。备份的流数据仍然保留在byte数组中。
public class RepeatableReadRequestWrapper extends HttpServletRequestWrapper {
private final byte[] bytes;
public RepeatableReadRequestWrapper(HttpServletRequest request, HttpServletResponse response) throws IOException {
super(request);
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
bytes = request.getReader().readLine().getBytes();
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() throws IOException {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() throws IOException {
return bais.read();
}
@Override
public int available() throws IOException {
return bytes.length;
}
};
}
}
3.定义一个拦截器
@Component
public class RepeatSubmitInterceptor implements HandlerInterceptor {
@Autowired
RedisCache redisCache;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
if (method.isAnnotationPresent(Authorization.class)) {
//请求参数字符串
String nowParams = "";
if (request instanceof RepeatableReadRequestWrapper) {
try {
nowParams = ((RepeatableReadRequestWrapper) request).getReader().readLine();
System.out.println("nowParams: " + nowParams);
//TODO 进行鉴权处理
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
return true;
}
}
4.定义一个过滤器
public class RepeatableRequestFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
if (StringUtils.startsWithIgnoreCase(request.getContentType(), "application/json")) {
RepeatableReadRequestWrapper requestWrapper = new RepeatableReadRequestWrapper(request, (HttpServletResponse) servletResponse);
filterChain.doFilter(requestWrapper,servletResponse);
return;
}
filterChain.doFilter(servletRequest, servletResponse);
}
}
5.配置类
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
RepeatSubmitInterceptor repeatSubmitInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**");
}
@Bean
FilterRegistrationBean<RepeatableRequestFilter> repeatableRequestFilterFilterRegistrationBean() {
FilterRegistrationBean<RepeatableRequestFilter> bean = new FilterRegistrationBean<>();
bean.setFilter(new RepeatableRequestFilter());
bean.addUrlPatterns("/*");
return bean;
}
}
6.测试类
@RestController
public class HelloController {
@Authorization
@PostMapping("/test")
public String authorization(@RequestBody User user) {
System.out.println(user);
return "succes";
}
}
测试结果

2.基于注解和AOP鉴权
1.定义一个鉴权标识注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Authorization {
}
2.定义AOP类
@Aspect
@Order(value = Integer.MAX_VALUE-1)
@Component
public class AuthorizationAspect {
private static Logger log = LoggerFactory.getLogger(AuthorizationAspect.class);
@Autowired
private AuthConfigService authConfigService;
@Before(value = "@annotation(com.llp.api.annotation.Authorization))")
public void authorization(JoinPoint joinPoint) throws Exception {
//获取请求参数
Object[] args = joinPoint.getArgs();
Signature signature = joinPoint.getSignature();
//获取方法签名
MethodSignature methodSignature = (MethodSignature) signature;
//获取Method对象
Method method = methodSignature.getMethod();
//判断方法是否被我们自定义的@Authorization注解修饰
if (method.isAnnotationPresent(Authorization.class)) {
//遍历请求参数
for (Object arg : args) {
//判断请求参数是否属于BaseConfigRequest类型
if (arg instanceof BaseConfigRequest) {
//属于,则对请求参数进行强转
BaseConfigRequest baseConfigRequest = (BaseConfigRequest) arg;
log.info("鉴权基类-baseConfigRequest:{}", ObjectUtils.getDisplayString(baseConfigRequest));
//获取鉴权id
String appId = baseConfigRequest.getAppId();
//获取密文
String cipherText = baseConfigRequest.getCipherText();
//通过鉴权id获取鉴权配置对象
EduAuthConfig authConfig = authConfigService.getAuthConfig(appId);
log.info("authConfig:{}", ObjectUtils.getDisplayString(authConfig));
//如果通过鉴权id没有查询到则抛出异常鉴权失败
Assert.notNull(authConfig, "未查询到appId对应的鉴权配置信息,鉴权失败");
//根据密文、私钥进行解密获取到鉴权key
String appKey = RSAUtil.decrypt(cipherText, authConfig.getPrivateKey());
log.info("解密后得到appKey:{}", appKey);
//如果鉴权key为空或者解密出来的鉴权key和配置的鉴权key不相同则抛出异常鉴权失败
if (appKey == null || !appKey.equals(authConfig.getAppKey())) {
throw new BaseException("鉴权参数错误,鉴权失败");
}
//鉴权通过结束循环
return;
}
}
}
}
}
3.定义一个鉴权基类
@Data
@ApiModel(value = "鉴权基类")
public class BaseConfigRequest<T> implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "鉴权Id")
@NotBlank(message = "鉴权id不能为空")
private String appId;
@ApiModelProperty(value = "密文")
@NotBlank(message = "密文不能为空")
private String cipherText;
@ApiModelProperty(value = "其他任意数据",notes = "在做鉴权时使用@Valid注解开启校验")
@Valid
private T data;
}
4.测试方法
@Authorization
@ApiOperation(value = "接收消息")
@RequestMapping(value = "/receiveMsg", method = RequestMethod.POST)
public BaseResult<String> receiveMsg(@Validated @RequestBody BaseConfigRequest<MessageSendRequest> request) {
return BaseResult.judgeOperate(messageService.receiveMsg(request));
}
边栏推荐
- Maidong Internet won the bid of Dajia Insurance Group
- The dplyr package filter function of R language filters the data in dataframe data through combinatorial logic (and logic). The content of one field is equal to one of the specified vectors, and the v
- Pancakeswap Technology: development principle of gripper robot system
- 使用 SSH 方式拉取代码
- Digital twin energy system, creating a "perspective" in the low-carbon era
- mysql.sock的概念是什么
- Tencent cloud released orbit, an automated delivery and operation and maintenance product, to promote enterprise applications to be fully cloud native
- 正则表达式
- The R language inputs the distance matrix to the hclust function for hierarchical clustering analysis. The method parameter specifies the distance calculation method between two combined data points,
- mysql查询视图命令是哪个
猜你喜欢

How to solve MySQL 1045 error in Linux

Face recognition 4- research on Baidu commercial solutions

Redis 原理 - Sorted Set (ZSet)

Opencv+YOLO-V3实现目标跟踪

MySQL触发器如何创建与删除

基于STM32F103ZET6库函数串口实验

PCB frame drawing - ad19

Basic operations such as MySQL startup under Windows platform
![Fill in the next right node pointer of each node [make good use of each point - > reduce the space-time complexity as much as possible]](/img/33/bda0a898bfe3503197026d1f62e851.png)
Fill in the next right node pointer of each node [make good use of each point - > reduce the space-time complexity as much as possible]

SRM supplier collaborative management system function introduction
随机推荐
What is the function of MySQL cursors
填充每个节点的下一个右侧节点指针[利用好每个点->尽可能降低时空复杂度]
开源仓库贡献 —— 提交 PR
Pancakeswap Technology: development principle of gripper robot system
selenium上传文件
What is a SCM system? What are the advantages of a supply chain management system?
Online text digit recognition list summation tool
Younger sister Juan takes you to learn JDBC - 2-day dash Day1
Openfeign use step polling strategy and weight log4j configuration of openfeign interceptor
使用 SSH 方式拉取代码
Segment tree and tree array template (copy and paste are really easy to use)
跨境独立站语言unicode转希伯来语
Basic operations such as MySQL startup under Windows platform
mysql. What is the concept of sock
How to use interrupt
小程序容器是什么技术?能助力物联网企业红海突围?
Leetcode daily question - 535 Encryption and decryption of tinyurl
mysql在linux中2003错误如何解决
R语言ggplot2可视化:使用patchwork包(直接使用加号+)将两个ggplot2可视化结果横向组合、接着再和第三个图像横向组合起来(三幅图各占比例为50%、25%、25%)
Sword finger offer 13 Robot range of motion (BFS)