System 解析(一)

包结构

在这里插入图片描述

这里记录一下学习eladmin项目的笔记,为了回顾,也为了共同学习。

项目结构

这里借鉴官网对项目结构的介绍:

  • eladmin-common:为系统的公共模块,各种工具类,公共配置存在该模块。
  • eladmin-system:为系统核心模块也是项目入口模块, 也是最终需要打包部署的模块。
  • eladmin-logging:为系统的日志模块,其他模块如果需要记录日志需要引入该模块。
  • eladmin-tools:为第三方工具模块,包含:图床、邮件、云存储、本地存储、支付宝
  • eladmin-generator:为系统的代码生成模块,代码生成的模板在system模块中。

详细结构

- eladmin-common 公共模块
    - annotation 为系统自定义注解
    - aspect 自定义注解的切面
    - base 提供了Entity、DTO基类和mapstruct的通用mapper
    - config 自定义权限实现、redis配置、swagger配置、Rsa配置等
    - exception 项目统一异常的处理
    - utils 系统通用工具类
- eladmin-system 系统核心模块(系统启动入口)
	- config 配置跨域与静态资源,与数据权限
	    - thread 线程池相关
	- modules 系统相关模块(登录授权、系统监控、定时任务、运维管理等)
- eladmin-logging 系统日志模块
- eladmin-tools 系统第三方工具模块
- eladmin-generator 系统代码生成模块

这里先详细看看eladmin-system的具体结构

eladmin-system

首先查看modules包下面的security包,这是由Spring Security构成的负责系统认证和权限管理的模块。
在这里插入图片描述

先查看其中的配置类,SecurityConfig.java,一般来说,都会有配置类继承类WebSecurityConfigurerAdapter

1.grantedAuthorityDefaults

首先使用@Bean注解,注册了grantedAuthorityDefaults

    @Bean
    GrantedAuthorityDefaults grantedAuthorityDefaults() {
        // 去除 ROLE_ 前缀
        return new GrantedAuthorityDefaults("");
    }

2.passwordEncoder

然后注册了密码加密方式

    @Bean
    public PasswordEncoder passwordEncoder() {
        // 密码加密方式
        return new BCryptPasswordEncoder();
    }

3.configure

重写configure,目的是为了配置自身需要的安全方式。

这里作者首先,寻找使用了自定义的注解@AnonymousAccess可以匿名访问的路由地址进行搜寻

// 搜寻匿名标记 url: @AnonymousAccess
        RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping) applicationContext.getBean("requestMappingHandlerMapping");
        Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = requestMappingHandlerMapping.getHandlerMethods();

当获取到这些请求类型之后,开始获取这些匿名请求的注解。具体的函数封装在了getAnonymousUrl函数中。

//获取匿名标记
Map<String, Set<String>> anonymousUrls = getAnonymousUrl(handlerMethodMap);
//getAnonymousUrl函数
private Map<String, Set<String>> getAnonymousUrl(Map<RequestMappingInfo, HandlerMethod> handlerMethodMap) {
        Map<String, Set<String>> anonymousUrls = new HashMap<>(6);
        Set<String> get = new HashSet<>();
        Set<String> post = new HashSet<>();
        Set<String> put = new HashSet<>();
        Set<String> patch = new HashSet<>();
        Set<String> delete = new HashSet<>();
        Set<String> all = new HashSet<>();
        for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethodMap.entrySet()) {
            HandlerMethod handlerMethod = infoEntry.getValue();
            AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class);
            if (null != anonymousAccess) {
                List<RequestMethod> requestMethods = new ArrayList<>(infoEntry.getKey().getMethodsCondition().getMethods());
                RequestMethodEnum request = RequestMethodEnum.find(requestMethods.size() == 0 ? RequestMethodEnum.ALL.getType() : requestMethods.get(0).name());
                switch (Objects.requireNonNull(request)) {
                    case GET:
                        get.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
                        break;
                    case POST:
                        post.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
                        break;
                    case PUT:
                        put.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
                        break;
                    case PATCH:
                        patch.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
                        break;
                    case DELETE:
                        delete.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
                        break;
                    default:
                        all.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
                        break;
                }
            }
        }
        anonymousUrls.put(RequestMethodEnum.GET.getType(), get);
        anonymousUrls.put(RequestMethodEnum.POST.getType(), post);
        anonymousUrls.put(RequestMethodEnum.PUT.getType(), put);
        anonymousUrls.put(RequestMethodEnum.PATCH.getType(), patch);
        anonymousUrls.put(RequestMethodEnum.DELETE.getType(), delete);
        anonymousUrls.put(RequestMethodEnum.ALL.getType(), all);
        return anonymousUrls;
    }

除此之外还定义securityConfigurerAdapter方法,返回的对象为TokenConfigurer

    private TokenConfigurer securityConfigurerAdapter() {
        return new TokenConfigurer(tokenProvider, properties, onlineUserService, userCacheClean);
    }

TokenConfigurer为一个类,下面看看,这个类的代码。

@RequiredArgsConstructor
public class TokenConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {

    private final TokenProvider tokenProvider;
    private final SecurityProperties properties;
    private final OnlineUserService onlineUserService;
    private final UserCacheClean userCacheClean;

    @Override
    public void configure(HttpSecurity http) {
        TokenFilter customFilter = new TokenFilter(tokenProvider, properties, onlineUserService, userCacheClean);
        http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
    }
}

这里涉及到以下知识:

  • @RequiredArgsConstructor
    • 注解在类上,会生成构造方法(可能带参数也可能不带参数)。

    注意:如果带参数,这个参数只能是以final修饰的未经初始化的字段或者是以@NonNull注解的未经初始化的字段。

    • 该注解还可以用@RequiredArgsConstructor(staticName="methodName")的形式生成一个指定名称的静态方法,返回一个调用相应的构造方法产生的对象。
// 使用注解
@RequiredArgsConstructor(staticName = "hangge")
public class Shape {
    private int x;
    @NonNull
    private double y;
    @NonNull
    private String name;
}
 
// 不使用注解
public class Shape {
    private int x;
    private double y;
    private String name;
 
    public Shape(double y, String name){
        this.y = y;
        this.name = name;
    }
 
    public static Shape hangge(double y, String name){
        return new Shape(y, name);
    }
}   
  • TokenFilter类的代码则如下,这是TokenFilter的构造方法。
    public TokenFilter(TokenProvider tokenProvider, SecurityProperties properties, OnlineUserService onlineUserService, UserCacheClean userCacheClean) {
        this.properties = properties;
        this.onlineUserService = onlineUserService;
        this.tokenProvider = tokenProvider;
        this.userCacheClean = userCacheClean;
    }
  • addFilterBefore(A,B.class)给A的序号比B小1,addFilterAfter(A,B.class)给A的序号比B大1。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值