springboot2 webflux集成spring security做权限登陆校验

一、主要pom依赖包

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.5.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-core</artifactId>
</dependency>
<!-- 使用redis存储session -->
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>

二、application root配置

@SpringBootApplication
//开启webflux
@EnableWebFlux
//使用redis存储session信息
@EnableRedisWebSession
public class AuthorityParentApplication {

	public static void main(String[] args) {
        Hooks.onOperatorDebug();
		SpringApplication.run(AuthorityParentApplication.class, args);
	}
}

三、权限校验配置

先把主要的配置类信息分别说一下,后面会有组合后的configuration类,类名为:SecurityConfig

1、过滤器配置

webflux security配置调用链信息的主类为:ServerHttpSecurity,里面有OAuth2,formlogin等登陆方式的默认配置

管理系统的话我们启用FormLoginSpec即刻,就是传统的cookie配session的登陆验证机制

/**
     * 此处的代码会放在SecurityConfig类中,此处只是摘要下,里面的handler在下文会详细介绍
     * @param http
     * @return
     */
@Bean
    SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) {
        ServerHttpSecurity.FormLoginSpec formLoginSpec = http.formLogin();
        formLoginSpec.authenticationSuccessHandler(createAuthenticationSuccessHandler())
                .loginPage("/login")
                .authenticationFailureHandler(createAuthenticationFailureHandler());
        return formLoginSpec.and()
                .csrf().disable()
                .httpBasic().disable()
                .authorizeExchange()
                .pathMatchers(AUTH_WHITELIST).permitAll()
                .anyExchange().authenticated()
                .and().build();
    }

最后调用ServerHttpSecurity的build方法,从源码中可以查看构造的filter调用链,及配置信息等

public SecurityWebFilterChain build() {
		if (this.built != null) {
			throw new IllegalStateException("This has already been built with the following stacktrace. " + buildToString());
		}
		this.built = new RuntimeException("First Build Invocation").fillInStackTrace();
		if (this.headers != null) {
			this.headers.configure(this);
		}
		WebFilter securityContextRepositoryWebFilter = securityContextRepositoryWebFilter();
		if (securityContextRepositoryWebFilter != null) {
			this.webFilters.add(securityContextRepositoryWebFilter);
		}
		if (this.httpsRedirectSpec != null) {
			this.httpsRedirectSpec.configure(this);
		}
		if (this.csrf != null) {
			this.csrf.configure(this);
		}
		if (this.cors != null) {
			this.cors.configure(this);
		}
		if (this.httpBasic != null) {
			this.httpBasic.authenticationManager(this.authenticationManager);
			this.httpBasic.configure(this);
		}
		if (this.formLogin != null) {
			this.formLogin.authenticationManager(this.authenticationManager);
			if (this.securityContextRepository != null) {
				this.formLogin.securityContextRepository(this.securityContextRepository);
			}
			this.formLogin.configure(this);
		}
		if (this.oauth2Login != null) {
			this.oauth2Login.configure(this);
		}
		if (this.resourceServer != null) {
			this.resourceServer.configure(this);
		}
		if (this.client != null) {
			this.client.configure(this);
		}
		this.loginPage.configure(this);
		if (this.logout != null) {
			this.logout.configure(this);
		}
		this.requestCache.configure(this);
		this.addFilterAt(new SecurityContextServerWebExchangeWebFilter(), SecurityWebFiltersOrder.SECURITY_CONTEXT_SERVER_WEB_EXCHANGE);
		if (this.authorizeExchange != null) {
			ServerAuthenticationEntryPoint authenticationEntryPoint = getAuthenticationEntryPoint();
			ExceptionTranslationWebFilter exceptionTranslationWebFilter = new ExceptionTranslationWebFilter();
			if (authenticationEntryPoint != null) {
				exceptionTranslationWebFilter.setAuthenticationEntryPoint(
					authenticationEntryPoint);
			}
			ServerAccessDeniedHandler accessDeniedHandler = getAccessDeniedHandler();
			if (accessDeniedHandler != null) {
				exceptionTranslationWebFilter.setAccessDeniedHandler(
						accessDeniedHandler);
			}
			this.addFilterAt(exceptionTranslationWebFilter, SecurityWebFiltersOrder.EXCEPTION_TRANSLATION);
			this.authorizeExchange.configure(this);
		}
		AnnotationAwareOrderComparator.sort(this.webFilters);
		List<WebFilter> sortedWebFilters = new ArrayList<>();
		this.webFilters.forEach( f -> {
			if (f instanceof OrderedWebFilter) {
				f = ((OrderedWebFilter) f).webFilter;
			}
			sortedWebFilters.add(f);
		});
        //sortedWebFilters中保存了登陆权限校验的所有filter信息
		sortedWebFilters.add(0, new ServerWebExchangeReactorContextWebFilter());
		return new MatcherSecurityWebFilterChain(getSecurityMatcher(), sortedWebFilters);
	}

2、自定义用户信息获取方式

获取用户信息的接口定义是:ReactiveUserDetailsService,官网的实现是:MapReactiveUserDetailsService,给出demo中是代码写死用户名密码、角色,并用此类存储。但实际中更多的从数据库中获取配置的用户角色信息,所以我们实现ReactiveUserDetailsService接口,自定义从mysql中获取用户信息的类,代码如下:

import com.sisheng.authority.common.enums.ErrorEnum;
import com.sisheng.authority.common.exception.BusinessException;
import com.sisheng.authority.repository.user.entity.SystemUser;
import com.sisheng.authority.servi
  • 0
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值