public class FormLoginSpec {
private final RedirectServerAuthenticationSuccessHandler defaultSuccessHandler;
private RedirectServerAuthenticationEntryPoint defaultEntryPoint;
private ReactiveAuthenticationManager authenticationManager;
private ServerSecurityContextRepository securityContextRepository;
private ServerAuthenticationEntryPoint authenticationEntryPoint; //认证端口,如果不设置,默认:RedirectServerAuthenticationEntryPoint("/login")
private boolean isEntryPointExplicit;
private ServerWebExchangeMatcher requiresAuthenticationMatcher; //设置自定义的认证路径,默认与loginPage相同
private ServerAuthenticationFailureHandler authenticationFailureHandler;
private ServerAuthenticationSuccessHandler authenticationSuccessHandler;
public ServerHttpSecurity.FormLoginSpec authenticationManager(ReactiveAuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
return this;
public ServerHttpSecurity.FormLoginSpec authenticationSuccessHandler(ServerAuthenticationSuccessHandler authenticationSuccessHandler) {
Assert.notNull(authenticationSuccessHandler, "authenticationSuccessHandler cannot be null");
this.authenticationSuccessHandler = authenticationSuccessHandler;
return this;
public ServerHttpSecurity.FormLoginSpec loginPage(String loginPage) {
this.defaultEntryPoint = new RedirectServerAuthenticationEntryPoint(loginPage);
this.authenticationEntryPoint = this.defaultEntryPoint; //设置默认的认证端口
if (this.requiresAuthenticationMatcher == null) {
this.requiresAuthenticationMatcher = ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, new String[]{loginPage});
} //认证方式默认为post、路径为:/loginPage
if (this.authenticationFailureHandler == null) {
this.authenticationFailureHandler = new RedirectServerAuthenticationFailureHandler(loginPage + "?error");
return this;
public ServerHttpSecurity.FormLoginSpec authenticationEntryPoint(ServerAuthenticationEntryPoint authenticationEntryPoint) {
this.authenticationEntryPoint = authenticationEntryPoint;
return this;
public ServerHttpSecurity.FormLoginSpec requiresAuthenticationMatcher(ServerWebExchangeMatcher requiresAuthenticationMatcher) {
this.requiresAuthenticationMatcher = requiresAuthenticationMatcher;
return this;
public ServerHttpSecurity.FormLoginSpec authenticationFailureHandler(ServerAuthenticationFailureHandler authenticationFailureHandler) {
this.authenticationFailureHandler = authenticationFailureHandler;
return this;
public ServerHttpSecurity.FormLoginSpec securityContextRepository(ServerSecurityContextRepository securityContextRepository) {
this.securityContextRepository = securityContextRepository;
return this;
public ServerHttpSecurity and() {
return ServerHttpSecurity.this;
public ServerHttpSecurity disable() {
ServerHttpSecurity.this.formLogin = null;
return ServerHttpSecurity.this;
protected void configure(ServerHttpSecurity http) {
if (this.authenticationEntryPoint == null) {
this.isEntryPointExplicit = false;
this.loginPage("/login"); //如果authenticationEntryPoint为null,loginPage默认为:/login
} else {
this.isEntryPointExplicit = true;
if (http.requestCache != null) {
ServerRequestCache requestCache = http.requestCache.requestCache;
this.defaultSuccessHandler.setRequestCache(requestCache);
if (this.defaultEntryPoint != null) {
this.defaultEntryPoint.setRequestCache(requestCache);
MediaTypeServerWebExchangeMatcher htmlMatcher = new MediaTypeServerWebExchangeMatcher(new MediaType[]{MediaType.TEXT_HTML});
htmlMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
ServerHttpSecurity.this.defaultEntryPoints.add(0, new DelegateEntry(htmlMatcher, this.authenticationEntryPoint));
AuthenticationWebFilter authenticationFilter = new AuthenticationWebFilter(this.authenticationManager);
authenticationFilter.setRequiresAuthenticationMatcher(this.requiresAuthenticationMatcher);
authenticationFilter.setAuthenticationFailureHandler(this.authenticationFailureHandler);
authenticationFilter.setAuthenticationConverter(new ServerFormLoginAuthenticationConverter());
authenticationFilter.setAuthenticationSuccessHandler(this.authenticationSuccessHandler);
authenticationFilter.setSecurityContextRepository(this.securityContextRepository);
http.addFilterAt(authenticationFilter, SecurityWebFiltersOrder.FORM_LOGIN);
private FormLoginSpec() {
this.defaultSuccessHandler = new RedirectServerAuthenticationSuccessHandler("/");
this.authenticationSuccessHandler = this.defaultSuccessHandler;
@Bean
public MapReactiveUserDetailsService initMapReactiveUserDetailsService(){
UserDetails userDetails= User.builder().username("gtlx")
.passwordEncoder(initPasswordEncoder()::encode)
.password("123456")
.authorities("ROLE_USER")
.build();
return new MapReactiveUserDetailsService(userDetails);
@Bean
public SecurityWebFilterChain initSecurityWebFilterChain(ServerHttpSecurity http){
http.formLogin().loginPage("/login").requiresAuthenticationMatcher(ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST,"/login/form"))
.and().authorizeExchange()
.pathMatchers("/hello").hasAuthority("ROLE_USER")
.pathMatchers("/**").permitAll();
http.csrf().disable();
return http.build();
@Bean
public PasswordEncoder initPasswordEncoder(){
return new BCryptPasswordEncoder();
*********************
controller 层
HelloController
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello(Principal principal){
return "hello "+principal.getName();
LoginController
@Controller
public class LoginController {
@RequestMapping("/login")
public String login(){
return "login";
*********************
login.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org" xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<meta charset="UTF-8">
<title>Title</title>
</head>
<form th:action="@{/login/form}" th:align="center"method="post">
username:<input type="text" name="username"><br>
password:<input type="text" name="password"><br>
<button>提交</button>
</form>
</body>
</html>
*************************
localhost:8080/hello
认证通过后,输出:hello gtlx
启用Spring WebFlux安全性
在你的应用程序首先使Webflux安全@EnableWebFluxSecurity
@SpringBootApplication
@EnableWebFluxSecurity
public class SecuredRestApplication {
创建一个InMemory UserDetailsService
定义一个自定义UserDetailsService bean,在其中添加具有密码和初始角色的User:
@Bean
public MapReactiveUserDetailsService userDetailsRepository() {
UserDetails user = User . withDefaultPasswordEncoder()
.username( " user " )
实现接口 AuthenticationFailureHandler 自定义认证成功处理器
@Component
public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse respons
在此项目中naocs服务器是通过mysql来进行连接的,nacos不用手动搭建服务器,对于开发者来说,上手很快。
1.2 Nacos安装和启动
nacos 的下载和启动方法请参考Nacos 官网。
在启动nacos2.01的时候,有个坑,默认启动方式是以集群的方式启动,需要修改, 直接使用命令启动
startup.sh -m standalone
1.3 注册中心客户端搭建
Pom依赖导入:
<dependency&.
ExceptionTranslationFilter
ExceptionTranslationFilter(Security Filter)允许将AccessDeniedException和AuthenticationException转换为HTTP响应。ExceptionTranslationFilter作为Security Filters之一插入到FilterChainProxy中。
首先,ExceptionTranslationFilter调用FilterChain.doFilter(reques
1. 创建一个登录页面,可以使用JSP、Thymeleaf等模板引擎来实现。
2. 在Spring Security配置文件中,配置登录页面的URL和处理登录请求的URL。
3. 在登录页面中,使用表单提交用户输入的用户名和密码。
4. 在Spring Security配置文件中,配置用户认证的方式,可以使用内存认证、数据库认证、LDAP认证等方式。
5. 在用户认证成功后,可以使用Spring Security提供的默认跳转页面,也可以自定义跳转页面。
6. 在用户认证失败后,可以在登录页面中显示错误信息,或者跳转到自定义的错误页面。
以上就是Spring Security自定义登录页面的基本步骤。