美文网首页
Spring boot + session + 注解 实现简单的

Spring boot + session + 注解 实现简单的

作者: 唐朝早晨 | 来源:发表于2020-05-11 17:34 被阅读0次

    写在前面:本文一共分两个部分,第一个部通过注解+session的形式实现接口的安全验证,第二个部分实现通过注解的形式实现简单的权限管理。


    安全验证部分

    0、基本配置

    pom.xml文件

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.2.7.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.rootchen</groupId>
        <artifactId>demo</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>demo</name>
        <description>权限验证</description>
    
        <properties>
            <java.version>1.8</java.version>
            <mybatisplus.version>3.0.7.1</mybatisplus.version>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <exclusions>
                    <exclusion>
                        <artifactId>spring-boot-starter-tomcat</artifactId>
                        <groupId>org.springframework.boot</groupId>
                    </exclusion>
                </exclusions>
            </dependency>
    
            <!-- undertow容器 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-undertow</artifactId>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <!-- 数据库 -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
            <!-- mybatis-plus依赖 -->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>${mybatisplus.version}</version>
            </dependency>
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus</artifactId>
                <version>${mybatisplus.version}</version>
            </dependency>
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-generator</artifactId>
                <version>${mybatisplus.version}</version>
            </dependency>
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-support</artifactId>
                <version>2.1.9</version>
            </dependency>
            <!-- 模板引擎 -->
            <dependency>
                <groupId>org.freemarker</groupId>
                <artifactId>freemarker</artifactId>
                <version>2.3.28</version>
            </dependency>
            <!-- java 工具包-->
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version>5.0.5</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
    

    application.properties

    server.port=8009
    ################
    #   数据库配置
    ################
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.datasource.username=用户名
    spring.datasource.password=密码
    spring.datasource.url=jdbc:mysql://localhost:3306/db_demo?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
    
    ####################
    # mybatis-plus 配置
    ####################
    
    # 如果是放在src/main/java目录下 classpath:/com/your package/*/mapper/*Mapper.xml
    # 如果是放在resource目录 classpath:/mapper/*Mapper.xml
    mybatis-plus.mapper-locations=classpath:/mapper/*Mapper.xml
    mybatis-plus.global-config.banner=false
    #主键类型  0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
    mybatis-plus.global-config.db-config.id-type=auto
    #字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
    mybatis-plus.global-config.db-config.field-strategy=not_null
    #驼峰下划线转换
    mybatis-plus.global-config.db-config.table-underline=true
    #逻辑删除配置(下面3个配置)
    # 逻辑删除全局值(1表示已删除,这也是Mybatis Plus的默认配置)
    mybatis-plus.global-config.db-config.logic-delete-value=1
    # 逻辑未删除全局值(0表示未删除,这也是Mybatis Plus的默认配置)
    mybatis-plus.global-config.db-config.logic-not-delete-value=0
    #配置返回数据库(column下划线命名&&返回java实体是驼峰命名),自动匹配无需as(没开启这个,SQL需要写as: select user_id as userId)
    mybatis-plus.configuration.map-underscore-to-camel-case=true
    #session过期时间
    server.servlet.session.timeout=30m
    

    1、目录结构

    目录结构

    2、文件内容

    2.0 NotAuth注解类

    import java.lang.annotation.*;
    
    /**
     * 免鉴权注解
     */
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    public @interface NotAuth {
    }
    

    2.1 MvcConfig.java

    //注入自己编写的拦截器
        @Bean
        public SecurityInterceptor securityInterceptor(){
            return new SecurityInterceptor();
        }
        
        //放行的url配置
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(securityInterceptor())
                    .excludePathPatterns("/static/*")
                    .excludePathPatterns("/error")
                    .addPathPatterns("/**");
        }
    

    2.2 mybatis-plus 配置
    mybatis-plus官网
    2.3 自定义返回结果
    参考这篇文章
    2.4 BaseExceptionHandler.java

    @RestControllerAdvice
    public class BaseExceptionHandler {
        private final static Logger logger = LoggerFactory.getLogger(BaseExceptionHandler.class);
          
        //空参数处理
        @ExceptionHandler(MethodArgumentNotValidException.class)
        public SR<List> handlerBindException(MethodArgumentNotValidException e) {
            BindingResult result = e.getBindingResult();
            List<String> errorList = new ArrayList<>();
            if (result.hasErrors()) {
    
                List<ObjectError> errors = result.getAllErrors();
    
                errors.forEach(p -> {
                    FieldError fieldError = (FieldError) p;
                    logger.error("Data check failure : object{" + fieldError.getObjectName() + "},field{" + fieldError.getField() +
                            "},errorMessage{" + fieldError.getDefaultMessage() + "}");
    
                    errorList.add(fieldError.getDefaultMessage());
                });
    
            }
            return SR.error(Const.CODE.EXCEPTION_PARAM.getCode(), Const.CODE.EXCEPTION_PARAM.getDesc(), errorList);
    
        }
      
        //登录处理
        @ExceptionHandler(LoginExceptionHandler.class)
        public SR loginExceptionHandler(LoginExceptionHandler e){
            logger.info(e.getMessage());
            return SR.error(Const.CODE.NEED_LOGIN.getCode(), Const.CODE.NEED_LOGIN.getDesc());
        }
        //其他异常处理
        @ExceptionHandler(RuntimeException.class)
        public SR runtimeExceptionHandler(RuntimeException e){
            logger.error(e.getMessage());
            return SR.errorMsg("系统错误");
        }
    

    2.5 LoginExceptionHandler

    public class LoginExceptionHandler extends RuntimeException{
    }
    

    2.6 SecurityCheck

    public class SecurityCheck {
        /**
         * 登录校验
         *
         * @param session
         * @return Boolean
         */
        public static Boolean isLoginSuccess(HttpSession session) {
            User user = (User) session.getAttribute(Const.CURRENT_USER);
            if (user != null) {
                return true;
            }
            return false;
        }
    
    }
    

    2.7 SecurityInterceptor

    public class SecurityInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
           if ( hasPermission(handler,request)){
               return true;
           }
           throw new LoginExceptionHandler("未登录");
        }
    
    
        /**
         * 接口权限判断
         * @param handler
         * @param request
         * @return
         */
        private boolean hasPermission(Object handler,HttpServletRequest request){
            if (handler instanceof HandlerMethod){
                HandlerMethod handlerMethod = (HandlerMethod) handler;
                //获取接口上的注解,如果有注解则放行,没有注解则进行验证
                NotAuth notAuth = handlerMethod.getMethod().getAnnotation(NotAuth.class);
                if (notAuth == null){
                    if (SecurityCheck.isLoginSuccess(request.getSession())){
                        return true;
                    }
                    return false;
                }
            }
            return true;
        }
    
        @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 {
        
        }
    }
    
    

    测试

    0 编写测试controller

    @RestController
    @RequestMapping("/demo/")
    public class UserController {
    
        @Autowired
        private UserMapper userMapper;
    
        //登录
        @NotAuth
        @PostMapping("login")
        public SR login(@Valid @RequestBody User user, HttpServletRequest request){
            //加密
            user.setPassword(DigestUtil.md5Hex(user.getPassword()));
            User user1 = userMapper.checkUser(user);
            if (user1 == null){
                return SR.error(Const.CODE.ERROR.getCode(),"用户名或者密码错误");
            }
            rrequest.getSession().setAttribute(Const.CURRENT_USER,user);
            return SR.okMsg(Const.CODE.SUCCESS.getDesc());
        }
    
        //注册
        @NotAuth
        @PostMapping("regist")
        public SR regist(@Valid @RequestBody User user){
            user.setPassword(DigestUtil.md5Hex(user.getPassword()));
            userMapper.insertUser(user);
            return SR.okMsg(Const.CODE.SUCCESS.getDesc());
        }
    
    
        //获取所有用户
        @GetMapping("/getAllUser")
        public SR getAllUser(){
            List<User> users = userMapper.selectAllUser();
            return SR.ok(users);
        }
        
        //退出登录
        @NotAuth
        @GetMapping("/logout")
        public SR Logout(HttpServletRequest request){
            request.getSession().removeAttribute(Const.CURRENT_USER);
            return SR.ok("登出成功");
        }
        
    }
    
    

    注:crud请自己去写

    接口上有NotAuth注解的都是不需要验证的,没有NotAuth都是需要验证的

    测试:
    未登录获取所有用户接口


    接口被打回

    注册用户


    接口成功访问
    登录
    当用户名密码为空时被打回
    密码为空
    用户名密码都输入

    再次访问获取所有用户接口


    注意在postman里测试session的时候
    把登录成功后的sessionid复制到第二个请求的cookie里




    最后一步登出测试




    再次访问获取所有用户接口

    这期就这样了~~

    相关文章

      网友评论

          本文标题:Spring boot + session + 注解 实现简单的

          本文链接:https://www.haomeiwen.com/subject/ezeynhtx.html