日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
SpringWebFluxSecurity結(jié)合R2DBC實(shí)現(xiàn)權(quán)限控制

環(huán)境:Springboot2.7.7

我們提供的服務(wù)有:成都網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站、微信公眾號開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、海東ssl等。為千余家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的海東網(wǎng)站制作公司

依賴管理


org.springframework.boot
spring-boot-starter-data-r2dbc


org.springframework.boot
spring-boot-starter-security


org.springframework.boot
spring-boot-starter-webflux


dev.miku
r2dbc-mysql
0.8.2.RELEASE

配置管理

spring:
r2dbc:
url: r2dbc:mysql://localhost:3306/testjpa?serverZoneId=GMT%2B8
username: root
password: 123123
pool:
initialSize: 100
maxSize: 200
maxCreateConnectionTime: 30s
---
logging:
level:
'[org.springframework.r2dbc]': DEBUG

實(shí)體對象,Repository,Service

@Table("t_users")
public class Users implements UserDetails {
@Id
private Integer id ;
private String username ;
private String password ;
}

這里實(shí)體對象實(shí)現(xiàn)了UserDetials,在后續(xù)配置的ReactiveUserDetailsService 配置返回值必須是UserDetails

Repository接口

public interface UsersRepository extends ReactiveSortingRepository {
Mono findByUsername(String username);
}

Service類

@Service
public class UsersService {

@Resource
private R2dbcEntityTemplate template;
@Resource
private UsersRepository ur ;

public Mono queryUserByUsername(String username) {
return ur.findByUsername(username) ;
}

public Mono queryUserByUsernameAndPassword(String username, String password) {
return ur.findByUsernameAndPassword(username, password) ;
}

public Flux queryUsers() {
return template.select(Users.class).all() ;
}

}

數(shù)據(jù)庫中插入幾條數(shù)據(jù)

單元測試

@SpringBootTest
class SpringBootWebfluxSecurity2ApplicationTests {

@Resource
private UsersService usersService ;

@Test
public void testQueryUserByUsername() throws Exception {
usersService.queryUserByUsername("admin")
.doOnNext(System.out::println)
.subscribe() ;
System.in.read() ;
}

}

輸出

2023-01-12 17:43:48.863 DEBUG 16612 --- [           main] o.s.w.r.r.m.a.ControllerMethodResolver   : ControllerAdvice beans: none
2023-01-12 17:43:48.896 DEBUG 16612 --- [ main] o.s.w.s.adapter.HttpWebHandlerAdapter : enableLoggingRequestDetails='false': form data and headers will be masked to prevent unsafe logging of potentially sensitive data
2023-01-12 17:43:49.147 INFO 16612 --- [ main] ringBootWebfluxSecurity2ApplicationTests : Started SpringBootWebfluxSecurity2ApplicationTests in 1.778 seconds (JVM running for 2.356)
2023-01-12 17:43:50.141 DEBUG 16612 --- [actor-tcp-nio-2] o.s.r2dbc.core.DefaultDatabaseClient : Executing SQL statement [SELECT t_users.id, t_users.username, t_users.password FROM t_users WHERE t_users.username = ?]
Users [id=3, username=admin, password=123123]

正常,接下來就是進(jìn)行Security的配置

@Configuration
@EnableReactiveMethodSecurity
public class ReactiveSecurityConfig {

// 根據(jù)用戶名查詢用戶信息
@Bean
public ReactiveUserDetailsService reativeUserDetailsService(UsersService usersService) {
return username -> usersService.queryUserByUsername(username).map(user -> {
return (UserDetails) user;
});
}
// 根據(jù)查詢出的用戶進(jìn)行密碼比對,沒有對密碼進(jìn)行加密所有就進(jìn)行簡單的equals比較
@Bean
public PasswordEncoder passwordEncoder() {
return new PasswordEncoder() {
@Override
public String encode(CharSequence rawPassword) {
return rawPassword.toString();
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return rawPassword.toString().equals(encodedPassword);
}
};
}
@Order(Ordered.HIGHEST_PRECEDENCE + 1)
@Bean
public SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) {
http.authorizeExchange((authorize) ->
authorize
// 配置資源訪問權(quán)限,對于靜態(tài)資源直接放行
.pathMatchers("/resources/**", "/favicon.ico").permitAll()
// /users開頭的接口必須擁有ROLE_ADMIN角色
.pathMatchers("/users/**").hasRole("ADMIN")
// /api開頭的接口通過自定義驗(yàn)證邏輯控制
.pathMatchers("/api/**").access((authentication, context) -> {
return authentication.map(auth -> {
if ("user1".equals(auth.getName())) {
return new AuthorizationDecision(false);
}
MultiValueMap params = context.getExchange().getRequest().getQueryParams();
List sk = params.get("sk");
if (sk == null || sk.get(0).equals("u")) {
return new AuthorizationDecision(false);
}
return new AuthorizationDecision(true);
});
}).anyExchange().authenticated());
// 異常處理
http.exceptionHandling(execSpec -> {
// 無權(quán)限時響應(yīng)策略
execSpec.accessDeniedHandler((exchange, denied) -> {
ServerHttpResponse response = exchange.getResponse() ;
response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
DataBuffer body = response.bufferFactory().allocateBuffer() ;
body.write("無權(quán)限 - " + denied.getMessage(), StandardCharsets.UTF_8) ;
return response.writeWith(Mono.just(body)) ;
}) ;
// 沒有登錄配置統(tǒng)一認(rèn)證入口,這里默認(rèn)系統(tǒng)提供的登錄頁面
execSpec.authenticationEntryPoint((exchange, ex) -> {
ServerHttpResponse response = exchange.getResponse() ;
response.getHeaders().add("Content-Type", "text/html;charset=UTF-8");
DataBuffer body = response.bufferFactory().allocateBuffer() ;
body.write("請先登錄 - " + ex.getMessage(), StandardCharsets.UTF_8) ;
return response.writeWith(Mono.just(body)) ;
}) ;
}) ;
http.csrf(csrf -> csrf.disable());
http.formLogin();
return http.build();
}

}

以上就是Security的配置。這里就不做測試了

原理

這里對實(shí)現(xiàn)的原理做簡單的接收,主要核心是WebFilter

自動配置類中

public class ReactiveSecurityAutoConfiguration {
// 這里通過注解啟用了Security功能
@EnableWebFluxSecurity
static class EnableWebFluxSecurityConfiguration {
}
}

EnableWebFluxSecurity

@Import({ ServerHttpSecurityConfiguration.class, WebFluxSecurityConfiguration.class,
ReactiveOAuth2ClientImportSelector.class })
@Configuration
public @interface EnableWebFluxSecurity {
}

這里有個重要的ServerHttpSecurityConfiguration和WebFluxSecurityConfiguration配置類

@Configuration(proxyBeanMethods = false)
class ServerHttpSecurityConfiguration {
// 該類用來自定義配置我們的信息,也就是上面我們自定義的SecurityWebFilterChain
// 通過ServerHttpSecurity構(gòu)建SecurityWebFilterChain
@Bean(HTTPSECURITY_BEAN_NAME)
@Scope("prototype")
ServerHttpSecurity httpSecurity() {
ContextAwareServerHttpSecurity http = new ContextAwareServerHttpSecurity();
return http.authenticationManager(authenticationManager())
.headers().and()
.logout().and();
}
}

WebFluxSecurityConfiguration

配置類最主要就是用來配置一個WebFilter

@Configuration(proxyBeanMethods = false)
class WebFluxSecurityConfiguration {
private List securityWebFilterChains;
// 注入當(dāng)前系統(tǒng)中的所有SecurityWebFilterChain,主要就是我們自定義實(shí)現(xiàn)的該類型
@Autowired(required = false)
void setSecurityWebFilterChains(List securityWebFilterChains) {
this.securityWebFilterChains = securityWebFilterChains;
}
@Bean(SPRING_SECURITY_WEBFILTERCHAINFILTER_BEAN_NAME)
@Order(WEB_FILTER_CHAIN_FILTER_ORDER)
WebFilterChainProxy springSecurityWebFilterChainFilter() {
return new WebFilterChainProxy(getSecurityWebFilterChains());
}
private List getSecurityWebFilterChains() {
List result = this.securityWebFilterChains;
if (ObjectUtils.isEmpty(result)) {
return Arrays.asList(springSecurityFilterChain());
}
return result;
}
}

WebFilterChainProxy核心過濾器

public class WebFilterChainProxy implements WebFilter {

private final List filters;
@Override
public Mono filter(ServerWebExchange exchange, WebFilterChain chain) {
return Flux.fromIterable(this.filters)
.filterWhen((securityWebFilterChain) -> securityWebFilterChain.matches(exchange)).next()
.switchIfEmpty(chain.filter(exchange).then(Mono.empty()))
.flatMap((securityWebFilterChain) -> securityWebFilterChain.getWebFilters().collectList())
.map((filters) -> new FilteringWebHandler(chain::filter, filters)).map(DefaultWebFilterChain::new)
.flatMap((securedChain) -> securedChain.filter(exchange));
}

}

以上就是WebFlux中應(yīng)用Security的原理


分享題目:SpringWebFluxSecurity結(jié)合R2DBC實(shí)現(xiàn)權(quán)限控制
本文來源:http://www.5511xx.com/article/ccscpdj.html