马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
MVC 与 WebFlux 关系
SpringSecurity 设置要采用响应式配置,基于 WebFlux 中 WebFilter 实现,与 Spring MVC 的 Security 是通过 Servlet 的 Filter 实现雷同,也是一系列 filter 组成的过滤链。
Reactor 与传统 MVC 配置对应:
webfluxmvc作用@EnableWebFluxSecurity@EnableWebSecurity开启 security 配置ServerAuthenticationSuccessHandlerAuthenticationSuccessHandler登录乐成 HandlerServerAuthenticationFailureHandlerAuthenticationFailureHandler登录失败 HandlerServerLogoutSuccessHandlerLogoutSuccessHandler注销乐成HandlerServerSecurityContextRepositorySecurityContextHolder认证信息存储管理ReactiveUserDetailsServiceUserDetailsService用户登录逻辑处置惩罚ReactiveAuthenticationManagerAuthorizationManager认证管理ReactiveAuthorizationManagerAccessDecisionManager鉴权管理ServerAuthenticationEntryPointAuthenticationEntryPoint未认证 HandlerServerAccessDeniedHandlerAccessDeniedHandler鉴权失败 HandlerAuthenticationWebFilterFilterSecurityInterceptor拦截器快速入门
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-security</artifactId>
- <version>2.2.5.RELEASE</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-gateway</artifactId>
- <version>2.2.6.RELEASE</version>
- </dependency>
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>fastjson</artifactId>
- <version>2.0.38</version>
- </dependency>
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- </dependency>
复制代码 内存管理用户信息
- @EnableWebFluxSecurity
- @Configuration
- public class SecurityConfig {
- @Bean
- public SecurityWebFilterChain filterChain(ServerHttpSecurity http) {
- http.httpBasic()
- .and()
- .authorizeExchange()
- .anyExchange()
- .authenticated();
- return http.build();
- }
- /**
- * 内存管理用户信息
- */
- @Bean
- public MapReactiveUserDetailsService userDetailsService() {
- UserDetails user = User.withDefaultPasswordEncoder()
- .username("user")
- .password("password")
- .roles("USER")
- .build();
- return new MapReactiveUserDetailsService(user);
- }
- }
复制代码 自定义登录、注销处置惩罚器
- @Component
- public class LoginSuccessHandler implements ServerAuthenticationSuccessHandler {
- @Override
- public Mono<Void> onAuthenticationSuccess(WebFilterExchange webFilterExchange, Authentication authentication) {
- return Mono.defer(() -> Mono.just(webFilterExchange.getExchange().getResponse()).flatMap(response -> {
- DataBufferFactory dataBufferFactory = response.bufferFactory();
- DataBuffer dataBuffer = dataBufferFactory.wrap("登录成功".getBytes());
- return response.writeWith(Mono.just(dataBuffer));
- }));
- }
- }
复制代码- @Component
- public class LoginFailHandler implements ServerAuthenticationFailureHandler {
- @Override
- public Mono<Void> onAuthenticationFailure(WebFilterExchange webFilterExchange, AuthenticationException exception) {
- return Mono.defer(() -> Mono.just(webFilterExchange.getExchange().getResponse()).flatMap(response -> {
- DataBufferFactory dataBufferFactory = response.bufferFactory();
- DataBuffer dataBuffer = dataBufferFactory.wrap("登录失败".getBytes());
- return response.writeWith(Mono.just(dataBuffer));
- }));
- }
- }
复制代码- @Component
- public class LogoutSuccessHandler implements ServerLogoutSuccessHandler {
- @Override
- public Mono<Void> onLogoutSuccess(WebFilterExchange exchange, Authentication authentication) {
- return Mono.defer(() -> Mono.just(exchange.getExchange().getResponse()).flatMap(response -> {
- DataBufferFactory dataBufferFactory = response.bufferFactory();
- DataBuffer dataBuffer = dataBufferFactory.wrap("logout success".getBytes());
- return response.writeWith(Mono.just(dataBuffer));
- }));
- }
- }
复制代码- @EnableWebFluxSecurity
- @Configuration
- public class SecurityConfig {
- @Resource
- private LoginSuccessHandler loginSuccessHandler;
- @Resource
- private LoginFailHandler loginFailHandler;
- @Resource
- private LogoutSuccessHandler logoutSuccessHandler;
- @Bean
- public SecurityWebFilterChain filterChain(ServerHttpSecurity http) {
- http.httpBasic()
- .and()
- .authorizeExchange()
- .anyExchange()
- .authenticated();
- http.formLogin()
- .authenticationSuccessHandler(loginSuccessHandler)
- .authenticationFailureHandler(loginFailHandler)
- .and()
- .logout()
- .logoutSuccessHandler(logoutSuccessHandler);
- return http.build();
- }
- /**
- * 内存管理用户信息
- */
- @Bean
- public MapReactiveUserDetailsService userDetailsService() {
- UserDetails user = User.withDefaultPasswordEncoder()
- .username("user")
- .password("password")
- .roles("USER")
- .build();
- return new MapReactiveUserDetailsService(user);
- }
- }
复制代码 自定义用户信息
- 仿照 MapReactiveUserDetailsService 编写获取用户认证类
- @Component
- public class UserDetailService implements ReactiveUserDetailsService, ReactiveUserDetailsPasswordService {
- private final Map<String, UserDetails> users = new HashMap<>();
- @Resource
- private PasswordEncoder passwordEncoder;
- @Override
- public Mono<UserDetails> findByUsername(String username) {
- User user = null;
- if ("user".equals(username)) {
- user = new User("user", passwordEncoder.encode("123456"), true, true, true, true, new ArrayList<>());
- }
- return Mono.justOrEmpty(user);
- }
- @Override
- public Mono<UserDetails> updatePassword(UserDetails user, String newPassword) {
- return Mono.just(user)
- .map(u ->
- User.withUserDetails(u)
- .password(newPassword)
- .build()
- )
- .doOnNext(u -> {
- this.users.put(user.getUsername().toLowerCase(), u);
- });
- }
- }
复制代码
- 仿照 AbstractUserDetailsReactiveAuthenticationManager 编写用户认证管理类
- @Component
- public class UserAuthenticationManager extends AbstractUserDetailsReactiveAuthenticationManager {
- @Resource
- private PasswordEncoder passwordEncoder;
- @Resource
- private ReactiveUserDetailsService userDetailService;
- @Resource
- private ReactiveUserDetailsPasswordService userDetailsPswService;
- private Scheduler scheduler = Schedulers.boundedElastic();
- private UserDetailsChecker preAuthenticationChecks = user -> {
- if (!user.isAccountNonLocked()) {
- logger.debug("User account is locked");
- throw new LockedException(this.messages.getMessage(
- "AbstractUserDetailsAuthenticationProvider.locked",
- "User account is locked"));
- }
- if (!user.isEnabled()) {
- logger.debug("User account is disabled");
- throw new DisabledException(this.messages.getMessage(
- "AbstractUserDetailsAuthenticationProvider.disabled",
- "User is disabled"));
- }
- if (!user.isAccountNonExpired()) {
- logger.debug("User account is expired");
- throw new AccountExpiredException(this.messages.getMessage(
- "AbstractUserDetailsAuthenticationProvider.expired",
- "User account has expired"));
- }
- };
- private UserDetailsChecker postAuthenticationChecks = user -> {
- if (!user.isCredentialsNonExpired()) {
- logger.debug("User account credentials have expired");
- throw new CredentialsExpiredException(this.messages.getMessage(
- "AbstractUserDetailsAuthenticationProvider.credentialsExpired",
- "User credentials have expired"));
- }
- };
- @Override
- public Mono<Authentication> authenticate(Authentication authentication) {
- final String username = authentication.getName();
- final String presentedPassword = (String) authentication.getCredentials();
- return retrieveUser(username)
- .doOnNext(this.preAuthenticationChecks::check)
- .publishOn(this.scheduler)
- .filter(u -> this.passwordEncoder.matches(presentedPassword, u.getPassword()))
- .switchIfEmpty(Mono.defer(() -> Mono.error(new BadCredentialsException("Invalid Credentials"))))
- .flatMap(u -> {
- boolean upgradeEncoding = this.userDetailsPswService != null
- && this.passwordEncoder.upgradeEncoding(u.getPassword());
- if (upgradeEncoding) {
- String newPassword = this.passwordEncoder.encode(presentedPassword);
- return this.userDetailsPswService.updatePassword(u, newPassword);
- }
- return Mono.just(u);
- })
- .doOnNext(this.postAuthenticationChecks::check)
- .map(u -> new UsernamePasswordAuthenticationToken(u, u.getPassword(), u.getAuthorities()) );
- }
- @Override
- protected Mono<UserDetails> retrieveUser(String username) {
- return userDetailService.findBysername(username);
- }
- }
复制代码- @EnableWebFluxSecurity
- @Configuration
- public class SecurityConfig {
- @Resource
- private LoginSuccessHandler loginSuccessHandler;
- @Resource
- private LoginFailHandler loginFailHandler;
- @Resource
- private LogoutSuccessHandler logoutSuccessHandler;
- @Resource
- private UserAuthenticationManager userAuthenticationManager;
- @Bean
- public SecurityWebFilterChain filterChain(ServerHttpSecurity http) {
- http.httpBasic()
- .and()
- .authorizeExchange()
- .anyExchange()
- .authenticated();
- http.formLogin()
- .authenticationManager(authenticationManager())
- .authenticationSuccessHandler(loginSuccessHandler)
- .authenticationFailureHandler(loginFailHandler)
- .and()
- .logout()
- .logoutSuccessHandler(logoutSuccessHandler);
- return http.build();
- }
- /**
- * 注册用户信息验证管理器,可按需求添加多个按顺序执行
- */
- @Bean
- public ReactiveAuthenticationManager authenticationManager() {
- LinkedList<ReactiveAuthenticationManager> managers = new LinkedList<>();
- managers.add(userAuthenticationManager);
- return new DelegatingReactiveAuthenticationManager(managers);
- }
- @Bean
- public PasswordEncoder passwordEncoder() {
- return new BCryptPasswordEncoder();
- }
- }
复制代码 权限注解
- @EnableWebFluxSecurity
- @EnableReactiveMethodSecurity
- @Configuration
- public class SecurityConfig {
- // ....
- }
复制代码- @RestController
- public class TestController {
- /**
- * 无效
- */
- @Secured({"ROLE_ADMIN"})
- @RequestMapping(value = "/test")
- public Mono<String> test() {
- return Mono.just("test");
- }
- /**
- * 有效
- */
- @PreAuthorize("hasRole('ADMIN')")
- @RequestMapping(value = "/test1")
- public Mono<String> test1() {
- return Mono.just("test1");
- }
- @Secured({"ROLE_TEST"})
- @RequestMapping(value = "/test2")
- public Mono<String> test2() {
- return Mono.just("test2");
- }
- }
复制代码 自定义权限处置惩罚器
- @Component
- public class AccessDeniedHandler implements ServerAccessDeniedHandler {
- @Override
- public Mono<Void> handle(ServerWebExchange exchange, AccessDeniedException denied) {
- return Mono.defer(() -> Mono.just(exchange.getResponse()).flatMap(response -> {
- DataBufferFactory dataBufferFactory = response.bufferFactory();
- DataBuffer dataBuffer = dataBufferFactory.wrap("permission denied".getBytes());
- return response.writeWith(Mono.just(dataBuffer));
- }));
- }
- }
复制代码- @EnableWebFluxSecurity
- @EnableReactiveMethodSecurity
- @Configuration
- public class SecurityConfig {
- @Resource
- private LoginSuccessHandler loginSuccessHandler;
- @Resource
- private LoginFailHandler loginFailHandler;
- @Resource
- private LogoutSuccessHandler logoutSuccessHandler;
- @Resource
- private UserAuthenticationManager userAuthenticationManager;
- @Resource
- private AccessDeniedHandler accessDeniedHandler;
- @Bean
- public SecurityWebFilterChain filterChain(ServerHttpSecurity http) {
- http.httpBasic()
- .and()
- .authorizeExchange()
- .anyExchange()
- .authenticated();
- http.formLogin()
- .authenticationManager(authenticationManager())
- .authenticationSuccessHandler(loginSuccessHandler)
- .authenticationFailureHandler(loginFailHandler)
- .and()
- .logout()
- .logoutSuccessHandler(logoutSuccessHandler)
- .and()
- .exceptionHandling()
- .accessDeniedHandler(accessDeniedHandler);
- return http.build();
- }
- /**
- * 注册用户信息验证管理器,可按需求添加多个按顺序执行
- */
- @Bean
- public ReactiveAuthenticationManager authenticationManager() {
- LinkedList<ReactiveAuthenticationManager> managers = new LinkedList<>();
- managers.add(userAuthenticationManager);
- return new DelegatingReactiveAuthenticationManager(managers);
- }
- @Bean
- public PasswordEncoder passwordEncoder() {
- return new BCryptPasswordEncoder();
- }
- }
复制代码 自定义认证处置惩罚器
- @Component
- public class AuthenticationEntryPoint implements ServerAuthenticationEntryPoint {
- @Override
- public Mono<Void> commence(ServerWebExchange exchange, AuthenticationException e) {
- return Mono.defer(() -> Mono.just(exchange.getResponse()).flatMap(response -> {
- DataBufferFactory dataBufferFactory = response.bufferFactory();
- DataBuffer dataBuffer = dataBufferFactory.wrap("Authentication fail".getBytes());
- return response.writeWith(Mono.just(dataBuffer));
- }));
- }
- }
复制代码- @EnableWebFluxSecurity
- @EnableReactiveMethodSecurity
- @Configuration
- public class SecurityConfig {
- @Resource
- private LoginSuccessHandler loginSuccessHandler;
- @Resource
- private LoginFailHandler loginFailHandler;
- @Resource
- private LogoutSuccessHandler logoutSuccessHandler;
- @Resource
- private UserAuthenticationManager userAuthenticationManager;
- @Resource
- private AccessDeniedHandler accessDeniedHandler;
- @Resource
- private AuthenticationEntryPoint authenticationEntryPoint;
- @Bean
- public SecurityWebFilterChain filterChain(ServerHttpSecurity http) {
- http.httpBasic()
- .and()
- .authorizeExchange()
- .anyExchange()
- .authenticated();
- http.formLogin()
- .authenticationManager(authenticationManager())
- .authenticationSuccessHandler(loginSuccessHandler)
- .authenticationFailureHandler(loginFailHandler)
- .and()
- .logout()
- .logoutSuccessHandler(logoutSuccessHandler)
- .and()
- .exceptionHandling()
- .accessDeniedHandler(accessDeniedHandler)
- .authenticationEntryPoint(authenticationEntryPoint);
- return http.build();
- }
- /**
- * 注册用户信息验证管理器,可按需求添加多个按顺序执行
- */
- @Bean
- public ReactiveAuthenticationManager authenticationManager() {
- LinkedList<ReactiveAuthenticationManager> managers = new LinkedList<>();
- managers.add(userAuthenticationManager);
- return new DelegatingReactiveAuthenticationManager(managers);
- }
- @Bean
- public PasswordEncoder passwordEncoder() {
- return new BCryptPasswordEncoder();
- }
- }
复制代码 自定义鉴权处置惩罚器
[code]@Slf4j@Componentpublic class AuthorizeConfigManager implements ReactiveAuthorizationManager { private final AntPathMatcher antPathMatcher = new AntPathMatcher(); @Override public Mono check(Mono authentication, AuthorizationContext authorizationContext) { return authentication.map(auth -> { ServerWebExchange exchange = authorizationContext.getExchange(); ServerHttpRequest request = exchange.getRequest(); Collection |