基于自定义注解手写权限控制

2020-03-28 01:52:24 1148

方法一: AOP 方法二: 拦截器

项目结构

dfb0a1159167469b9600d017d78fe5aa.png

项目依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
</dependencies>

配置

spring:
  aop:
    proxy-target-class: true

定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Role {
    /**
     * 角色名 默认值:游客
     * @return
     */
    String value() default "NORMAL";
}

控制层

package com.github.controller;


import com.github.annotations.Role;
import com.github.entity.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpSession;


@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private HttpSession session;

    /**
     * 登录
     *
     * @param username
     * @param password
     */
    @Role
    @PostMapping("/login")
    public Result login(String username, String password) {

        if ("admin".equals(username)) {
            session.setAttribute(username, "ADMIN");
        } else {
            session.setAttribute(username, "USER");
        }

        return Result.resultFactory("登录成功", 200);
    }

    @Role("USER")
    @GetMapping("/user")
    public Result user() {
        return Result.resultFactory("访问成功", 200, "USER权限");
    }

    @Role("ADMIN")
    @GetMapping("/admin")
    public Result admin() {
        return Result.resultFactory("访问成功", 200, "ADMIN权限");
    }


}

响应信息类

package com.github.entity;

import com.fasterxml.jackson.annotation.JsonInclude;

import java.util.Date;

@JsonInclude(JsonInclude.Include.NON_NULL)
public class Result {
    private Date timestamp;
    private Integer status;
    private String error;
    private String message;
    private String path;
    private Object data;

    private Result() {
    }

    @Override
    public String toString() {
        return "Result{" +
                "timestamp=" + timestamp +
                ", status=" + status +
                ", error='" + error + '\'' +
                ", message='" + message + '\'' +
                ", path='" + path + '\'' +
                ", data=" + data +
                '}';
    }

    getter&setter...

    public static Result resultFactory(String message, Integer status, Object data) {
        Result result = new Result();
        result.setTimestamp(new Date());
        result.setMessage(message);
        result.setStatus(status);
        result.setData(data);
        return result;
    }

    public static Result resultFactory(String message, Integer status) {
        Result result = new Result();
        result.setTimestamp(new Date());
        result.setMessage(message);
        result.setStatus(status);
        return result;
    }
}

切面类


package com.github.aop;


import com.github.annotations.Role;
import com.github.controller.UserController;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;


@Aspect
@Component
public class UserAspect {

    @Autowired
    private HttpSession session;

    @Autowired
    private HttpServletRequest request;

    @Pointcut("execution(public * com.github.controller.*.*(..))")
    public void LogAspect() {
        System.out.println("切入点");
    }

    @Before("LogAspect()")
    public void doBefore(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature)signature;
        Method targetMethod = methodSignature.getMethod();
        Role roleAnnotation = targetMethod.getAnnotation(Role.class);
        String nameKey = request.getHeader("name");
        String role = (String)session.getAttribute(nameKey);

        if (roleAnnotation.value().equals("NORMAL")) {
            System.out.println("游客访问");
        } else if (roleAnnotation.value().equals(role)) {
            System.out.println("权限校验通过");
        } else {
            throw new RuntimeException("权限不足");
        }

    }

}

启动测试

  • 登录
  • 访问user接口
  • 访问admin接口
  • 用admin登录后再次访问admin接口

项目链接 提取码:hi7m

但要注意此项目定义的aop发生在SpringMVC的参数注入之后, 即前端传入的json参数被转为java对象后, 才会执行aop内的逻辑, 在一些场景下并不适用

方法二:

使用org.springframework.web.servlet.HandlerInterceptor这个接口

实现这个方法

boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception

其中handler参数可以强转为org.springframework.web.method.HandlerMethod, 该对象提供这个方法

Role role = ((HandlerMethod) handler).getMethodAnnotation(Role.class);

也能实现权限判断

Spring RedisTemplate Scan

keys 不能用, 那就只能用scan了public static Set<String> scan(RedisTemplate<String, String> redisTemplate, String pattern) { return redisTemplate.execute((Re
2024-10-30

Shiro与SpringAOP冲突导致无法请求到Controller

各依赖版本org.crazycake:shiro-redis-spring-boot-starter:3.2.1org.springframework.boot:spring-boot-starter-aop:2.3.0.RELEASE有个配置如下@Bean public static Defaul
2023-04-16

Spring的cglib代理类无法取到被代理类的成员属性

cglib的原理是生成一个被代理类的子类进行增强, 那么为什么子类访问不到父类的属性呢@Service public class AopTestService { public String value = "hello world"; @Transactional pu
2023-04-14

Spring循环依赖与三级缓存

常见的循环依赖@Component public class Aoo { @Autowired Boo boo; } @Component public class Boo { @Autowired Aoo aoo; } A依赖B B依赖A首先判断三级缓存中存不存在
2023-03-30
观察者模式与SpringBoot应用

观察者模式与SpringBoot应用

当对象间存在一对多关系时, 则使用观察者模式(Observer Pattern). 比如, 当一个对象被修改时, 则会自动通知依赖它的对象.优点:观察者和被观察者是抽象耦合的建立一套触发机制SpringBoot应用场景在SpringBoot启动流程中org.springframework.boot.
2021-11-30

Cron 表达式 星期建议使用 MON 等单词缩写

在spring提供的定时任务框架中@Scheduled(cron = "0 0 16 ? * 1") 1指周一但, 其他cron工具中, 1指周日区别就在于, spring的一周从周一开始, 而其他工具从周日开始判断可能是spring对时区做了判断, 动态切换但暂未验证而使用 MON 表示 周一,
2021-07-19

Spring自定义注解加载和使用

Spring在扫描类信息的使用只会判断被@Component注解的类所以任何自定义的注解只要带上@Component(当然还要有String value() default "";的方法,因为Spring的Bean都是有beanName唯一标示的)都可以被Spring扫描到,并注入容器内例: Spr
2020-12-28
AOP拦截controller方法注入参数 代替@RequestBody

AOP拦截controller方法注入参数 代替@RequestBody

效果如下加上@Pass放弃aop拦截注入,使用spring mvc的参数注入核心方法package com.github.aop; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxm
2020-09-16

@Transactional可在抽象类上定义,且能生效

定义一个抽象类 import com.shopping.base.repository.sync.ipos.coupon.IposCzklbRepository; import org.springframework.beans.factory.annotation.Autowired; impor
2020-07-28

多数据源 单库操作事务不回滚

项目配置了多数据源,之前操作主数据源,直接加上@Transactional(rollbackFor = Exception.class),没有任何问题最近操作其他数据源并做测试的时候,发现int i = 1 / 0并不会回滚,各种排查,从数据库引擎到注解@Transactional使用规范和异常处理
2020-07-27
手写Spring、SpringMVC

手写Spring、SpringMVC

目前实现了以下注解@Autowired 从容器中自动注入@Bean 标记方法返回值加入容器管理@Component 标记此类加入容器管理@RestController 标记此类为Rest风格的控制器 结果默认转为json@RequestMapping 前置匹配路径@GetMapping 匹配一个Ge
2020-07-01
基于自定义注解手写权限控制

基于自定义注解手写权限控制

方法一: AOP 方法二: 拦截器项目结构项目依赖<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-w
2020-03-28

如何在Java中替换多个if语句

1. 概述选择结构是任何编程语言的重要组成部分。但是我们编写了大量嵌套的if语句,这使得我们的代码更加复杂和难以维护。 在本教程中,我们将介绍替换嵌套if语句的各种方法。 让我们探索如何简化代码的不同选项。2. 案例研究我们经常遇到涉及很多条件的业务逻辑,并且每个都需要不同的处理。为了演示,我们以C
2020-03-28
Java中方法的参数传递机制

Java中方法的参数传递机制

来看一段代码 public class Man { private String name; private Integer age; public String getName() { return name; } publi
2020-03-28

SpringDataRedis 常用操作

//向redis里存入数据和设置缓存时间 stringRedisTemplate.opsForValue().set("test", "100",60*10,TimeUnit.SECONDS); //根据key获取缓存中的val stringRedisTemplate.opsForValue().
2020-03-28

freemarker 时间显示不正常 设置时区

项目在本地开发的时候显示正常,部署上服务器就一直差8个小时,最后发现freemarker官方文档有这样的说明time_zone:时区的名称来显示并格式化时间。 默认情况下,使用JVM的时区。 也可以是 Java 时区 API 接受的值,或者 "JVM default" (从 FreeMarker 2
2020-03-28
IDEA 2019.1 xml 不高亮

IDEA 2019.1 xml 不高亮

前几天更新了idea后,发现xml里的代码都没有了高亮,变得跟记事本一个德性了打开setting ,搜索 File Types,找到xml项, 查看下方的匹配格式,果然没有xml,(idea真是厉害)点击右方的+,输入*.xml,点击ok,解决问题
2020-03-28

npm install 淘宝镜像

npm install --registry=https://registry.npm.taobao.org
2020-03-28
Java中方法的参数传递机制

Java中方法的参数传递机制

来看一段代码 public class Man { private String name; private Integer age; public String getName() { return name; } publi
2020-03-28
基于自定义注解手写权限控制

基于自定义注解手写权限控制

方法一: AOP 方法二: 拦截器项目结构项目依赖<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-w
2020-03-28

Docker 部署 详细全过程 附代码

Docker 部署本站 全过程环境:CentOS7.61. 安装Docker其他版本CentOS可以参考这个https://help.aliyun.com/document_detail/187598.html查看本机内核版本,内核版本需高于 3.10uname -r 确保 yum 包最新yum u
2020-03-28

SpringBoot 启动普通java工程

引入依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>2.0.9</version> </dependency>
2020-03-28

Vue.js DOM操作

<template> <input type="button" @click="reply($event)" value="回复"> </template> export default { methods: { replyFun(e) {
2020-03-29
CentOS7编译调试OpenJDK12

CentOS7编译调试OpenJDK12

1. 下载源码https://hg.openjdk.java.net/jdk/jdk12点击左侧的browse,再点击zip,就可以下载zip格式的源码压缩包。unzip xxx.zip 解压文件2. 安装jdkyum install java-11-openjdk-devel -y3. 运行con
2020-04-23
编写自己的Spring Boot Starter

编写自己的Spring Boot Starter

1.新建一个maven项目命名规则统一是xxx-spring-boot-starter完整pom.xml<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"
2020-06-29