通用权限认证要点记录

通用权限认证要点记录

一、自定义starter

1、项目结构

自定义Starter

2、自定义注解

@Target(value = ElementType.METHOD)	
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {
   /**
    * 对方法进行描述
    */
	String desc() default "";
}

@Target()定义注解的作用目标(作用域),枚举类ElementType包含以下:

TYPE:接口、类、枚举、注解
FIELD:字段枚举的常量
METHOD:方法PARAMETER:方法参数
CONSTRUCTOR:构造函数
LOCAL_VARIABLE:局部变量
ANNOTATION_TYPE:注解
PACKAGE:包
TYPE_PARAMETER:参数类型声明
TYPE_USE:使用的类型

@Retention()用来指示其它注解类型保留的生命周期,枚举类RetentionPolicy包含一下三种策略:

SOURCE:注解只会存在源代码中,将会被编译器丢弃
CLASS:注解将会保留到class文件阶段,但是在加载如vm的时候会被抛弃
RUNTIME:注解不单会被保留到class文件阶段,而且也会被vm加载进虚拟机的时候保留

3、注解处理器的依赖

    <!--配置处理器-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>

spring-boot-configuration-processor
注解处理器,在编译阶段运行,一般在maven的声明中optional为 true
为自定义的配置类生成元数据信息,方便自定义配置信息

4、拦截器编写

//第一种写法 实现HandlerInterceptor接口
public class MyLogInterceptor implements HandlerInterceptor {
	@Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }
//第二种写法 继承HandlerInterceptorAdapter
public class MyLogInterceptor extends HandlerInterceptorAdapter{}
}

HandlerMethod handlerMethod = (HandlerMethod)handler;
Method method = handlerMethod.getMethod();//获得被拦截的方法对象
MyLog myLog = method.getAnnotation(MyLog.class);//获得方法上的注解

5、配置拦截器

/**
 * 配置类,用于自动配置拦截器、参数解析器等web组件
 */
@Configuration
public class SpringMvcConfiguration implements WebMvcConfigurer {
    //注册自定义日志拦截器
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyLogInterceptor()).addPathPatterns("/**");
    }
}

注意事项

如果自定义starter的包名和项目包名不一致的话,所有需要扫描的注解(@Configuration,@Compent)需要在XXXXAutoConfig类中使用(@Import)导入

二、配置swagger2_3.0

  • 在pom文件中添加依赖坐标:
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-boot-starter</artifactId>
    <version>3.0.0</version>
</dependency>
  • 在启动类中上增加注解@EnableOpenApi
  • 根据个人情况配置一些接口例子
  • 启动SpringBoot,访问swagger界面:http://localhost:8080/swagger-ui/index.html
  • Failed to start bean ‘documentationPluginsBootstrapper’
    错误原因:Springfox使用的路径匹配是基于AntPathMatcher的,而Spring Boot 2.6.X使用的是PathPatternMatcher
spring: 
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher

三、配置Dozer

  1. 在pom文件中添加依赖坐标:
<dependency>
    <groupId>com.github.dozermapper</groupId>
    <artifactId>dozer-spring-boot-starter</artifactId>
    <version>6.5.0</version>
</dependency>
  1. 在resources/dozer/目录下创建dozer的全局配置文件global.dozer.xml
<?xml version="1.0" encoding="UTF-8"?>
<mappings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns="http://dozermapper.github.io/schema/bean-mapping"
          xsi:schemaLocation="http://dozermapper.github.io/schema/bean-mapping 
                              http://dozermapper.github.io/schema/bean-mapping.xsd">
    <!--
    全局配置:
    <date-format>表示日期格式
     -->
    <configuration>
        <date-format>yyyy-MM-dd</date-format>
    </configuration>
</mappings>

注:全局配置文件名称可以任意
3. 在resources/dozer/目录下创建dozer的映射文件biz.dozer.xml,也可以使用@Mapping("字段名")的方式,不过注解只适用于简单的映射方式

<?xml version="1.0" encoding="UTF-8"?>
<mappings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns="http://dozermapper.github.io/schema/bean-mapping"
          xsi:schemaLocation="http://dozermapper.github.io/schema/bean-mapping
                             http://dozermapper.github.io/schema/bean-mapping.xsd">
    <!--描述两个类中属性的对应关系,对于两个类中同名的属性可以不映射-->
    <mapping date-format="yyyy-MM-dd">
        <class-a>com.itheima.entity.UserEntity</class-a>
        <class-b>com.itheima.dto.UserDTO</class-b>
        <field>
            <a>id</a>
            <b>userId</b>
        </field>
        <field>
            <a>name</a>
            <b>userName</b>
        </field>
        <field>
            <a>age</a>
            <b>userAge</b>
        </field>
    </mapping>
    <!--
    可以使用map-id指定映射的标识,在程序中通过此标识来确定使用当前这个映射关系
    -->
    <mapping date-format="yyyy-MM-dd" map-id="user">
        <class-a>com.itheima.entity.UserEntity</class-a>
        <class-b>com.itheima.dto.UserDTO</class-b>
        <field>
            <a>id</a>
            <b>userId</b>
        </field>
        <field>
            <a>name</a>
            <b>userName</b>
        </field>
        <field>
            <a>age</a>
            <b>userAge</b>
        </field>
    </mapping>
</mappings>
  1. 编写application.yml文件,将写好的映射文件添加进去
dozer:
  mappingFiles:
    - classpath:dozer/global.dozer.xml
    - classpath:dozer/biz.dozer.xml
  1. 使用dozer
//加载Mapper
 @Autowired
    private Mapper mapper;
    //使用map
    mapper.map(userDTO,user,"user");

map有四种:

//Object source源对象 | Object destination目标对象 
//Class<T> destinationClass对象类 | mapId映射文件中指定映射关系的id
<T> T map(Object source, Class<T> destinationClass) throws MappingException;
void map(Object source, Object destination) throws MappingException;
<T> T map(Object source, Class<T> destinationClass, String mapId) throws MappingException;
void map(Object source, Object destination, String mapId) throws MappingException;
  1. 对list或者set进行转换
    如果直接使用map进行转换,如创建两个ArrayList<Person> plist 和 ArrayList<Student> slist,将前者转化成后者即mapper.map(plist ,slist),只会用Person替换Student,而不是获得ArrayList<Student>。所以想要对list,set进行转换需要对其中元素循环遍历进行转换,如下:
 /**
     * 将集合转成集合
     * List<A> -->  List<B>
     *
     * @param sourceList       源集合
     * @param destinationClass 待转类型
     * @param <T>
     * @return
     */
    public <T, E> List<T> mapList(Collection<E> sourceList, Class<T> destinationClass) {
        if (sourceList == null || sourceList.isEmpty() || destinationClass == null) {
            return Collections.emptyList();
        }
        List<T> destinationList = sourceList.stream()
                .filter(item -> item != null)
                .map((sourceObject) -> mapper.map(sourceObject, destinationClass))
                .collect(Collectors.toList());

        return destinationList;
    }
  /**
     * Set<A> -->  Set<B>
     */
    public <T, E> Set<T> mapSet(Collection<E> sourceList, Class<T> destinationClass) {
        if (sourceList == null || sourceList.isEmpty() || destinationClass == null) {
            return Collections.emptySet();
        }
        return sourceList.stream().map((sourceObject) -> mapper.map(sourceObject, destinationClass)).collect(Collectors.toSet());
    }

四、hibernate-validator后端校验

后端校验:主要是保证数据安全可靠

  1. hibernate-validator包含的注解
注解说明
@AssertTrue用于boolean字段,该字段只能为true
@AssertFalse用于boolean字段,该字段只能为false
@CreditCardNumber对信用卡号进行一个大致的验证
@DecimalMax只能小于或等于该值
@DecimalMin只能大于或等于该值
@Email检查是否是一个有效的email地址
@Future检查该字段的日期是否是属于将来的日期
@Length(min=,max=)检查所属的字段的长度是否在min和max之间,只能用于字符串
@Max该字段的值只能小于或等于该值
@Min该字段的值只能大于或等于该值
@NotNull不能为null
@NotBlank不能为空,检查时会将空格忽略
@NotEmpty不能为空,这里的空是指空字符串
@Pattern(regex=)被注释的元素必须符合指定的正则表达式
@URL(protocol=,host,port)检查是否是一个有效的URL,如果提供了protocol,host等,则该URL还需满足提供的条件
  1. spring-boot-starter-web中已经依赖了hibernate-validator,所以不需要单独添加了
  2. 使用方式如下:

在对象字段上添加验证用的注解:
如:@NotNull(message = “用户id不能为空”)
@NotEmpty(message = “用户名不能为空”) @Length(max = 50, message = “用户名长度不能超过50”)
@Max(value = 80,message = “年龄最大为80”) @Min(value = 18,message = “年龄最小为18”)
@Pattern(regexp = “[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$”,message = “邮箱格式不正确”)

添加@Validated //开启校验功能,这个注解可以添加到类,方法,参数上,

@Validated
public class UserController {
   //简单数据类型校验
   @RequestMapping("/delete")
   public String delete(@NotBlank(message = "id不能为空") String id){
       System.out.println("delete..." + id);
       return "OK";
   }
   //对象属性校验
   @RequestMapping("/save")
   public String save(@Validated User user){
       System.out.println("save..." + user);
       return "OK";
   }
}
  1. 创建ValidatorConfiguration类,指定校验时使用快速失败返回模式
    通过控制台的输出可以看到,校验框架将我们的多个属性都进行了数据校验(默认行为),如果我们希望只要有一个属性校验失败就直接返回提示信息,后面的属性不再进行校验了该如何实现呢?
public class ValidatorConfiguration {
    @Bean
    public Validator validator() {
        ValidatorFactory validatorFactory = 
            Validation.byProvider(HibernateValidator.class)
                .configure()
                //快速失败返回模式
                .addProperty("hibernate.validator.fail_fast", "true")
                .buildValidatorFactory();
        return validatorFactory.getValidator();
    }

    /**
     * 开启快速返回
     * 如果参数校验有异常,直接抛异常,不会进入到 controller,使用全局异常拦截进行拦截
     */
    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        MethodValidationPostProcessor postProcessor = 
            new MethodValidationPostProcessor();
        /**设置validator模式为快速失败返回*/
        postProcessor.setValidator(validator());
        return postProcessor;
    }
}
  1. 创建注解EnableFormValidator用于控制快速失败返回模式的开启
/**
 * 在启动类上添加该注解来启动表单验证功能---快速失败返回模式
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(ValidatorConfiguration.class)
public @interface EnableFormValidator {
}
  1. 在启动类上加入EnableFormValidator注解,开启快速失败返回模式
@SpringBootApplication
@EnableFormValidator
public class HibernateValidatorApp {
    public static void main(String[] args) {
        SpringApplication.run(HibernateValidatorApp.class,args);
    }
}

五、防跨站脚本攻击(XSS)

XSS介绍

XSS:跨站脚本攻击(Cross Site Scripting),为不和 CSS混淆,故将跨站脚本攻击缩写为XSS。XSS是指恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。有点类似于sql注入。
XSS攻击原理:
HTML是一种超文本标记语言,通过将一些字符特殊地对待来区别文本和标记,例如,小于符号(<)被看作是HTML标签的开始,之间的字符是页面的标题等等。当动态页面中插入的内容含有这些特殊字符时,用户浏览器会将其误认为是插入了HTML标签,当这些HTML标签引入了一段JavaScript脚本时,这些脚本程序就将会在用户浏览器中执行。所以,当这些特殊字符不能被动态页面检查或检查出现失误时,就将会产生XSS漏洞。

AntiSamy介绍

AntiSamy是OWASP的一个开源项目,通过对用户输入的 HTML / CSS / JavaScript 等内容进行检验和清理,确保输入符合应用规范。AntiSamy被广泛应用于Web服务对存储型和反射型XSS的防御中。

AntiSamy使用

  1. 添加maven坐标
<dependency>
  <groupId>org.owasp.antisamy</groupId>
  <artifactId>antisamy</artifactId>
</dependency>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值