【SpringSecurity】默认的表单登录逻辑、DefaultLoginPageConfigurer FormLoginConfigurer的区别

之前已经学过了springsecurity,今天在学习spring-security-oauth2-authorization-server时要配置自定义的登陆页面,突然有点懵,发现对security默认的表单登录逻辑的配置还不是特别熟悉,花了些时间才捋顺配置逻辑,现在就记录一下。

目录

A1.登录模块的配置及使用(这里是使用默认提供的表单登录模式哦~)

B1.代码配置

B2.运行代码后的使用逻辑

B3.动图操作

A2.上述逻辑的代码分析

B1.SecurityFilterChain的配置逻辑

C1.filter对应的Configurer

C2.ExceptionHandlingConfigurer   --->  ExceptionTranslationFilter

C3.DefaultLoginPageConfigurer   --->  DefaultLoginPageGeneratingFilter + DefaultLogoutPageGeneratingFilter

C4.LogoutConfigurer   ---> LogoutFilter

C6.FormLoginConfigurer   --->  UsernamePasswordAuthenticationFilter

A3.总结

B1.默认的表单登录逻辑

注意:登录认证拦截器的核心是AuthenticationManager,我们想自定义登录认证拦截器还要考虑AuthenticationManager哒!

B2.DefaultLoginPageConfigurer 、FormLoginConfigurer的区别


 

A1.登录模块的配置及使用(这里是使用默认提供的表单登录模式哦~)

B1.代码配置

首先先看一下登录模块的配置(这里是使用默认提供的表单登录模式哦~):

-----------------------配置类
@Configuration
public class WebSecurityConfiguration {

    /**
     * @Description: spring security 默认的安全策略
     * @param http
     * @Return: org.springframework.security.web.SecurityFilterChain
     */
    @Bean
    SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {

        http.authorizeRequests(authorizeRequests -> authorizeRequests
                .antMatchers("/test/permit").permitAll() // 开放自定义的部分端点
                .anyRequest().authenticated()) // 其余都需要登录
        .formLogin(); //配置表单登录模式

        return http.build();
    }
}


-----------------------端点类

@RestController
@RequestMapping("/test")
public class TestController {

    @GetMapping("/auth")
    public R auth(){
        Principal principal = SecurityContextHolder.getContext().getAuthentication();
        System.out.println(principal);
        return R.ok(principal);
    }

    @GetMapping("/permit")
    public R permit(){
        return R.ok("/permit接口访问成功");
    }

}


B2.运行代码后的使用逻辑

运行上述程序,按照下面的逻辑进行使用:

1.访问需要登录认证的资源127.0.0.1:8080/test/auth(GET),会被FilterSecurityInterceptor拦截到,发现未登录就会抛出异常,然后被ExceptionTranslationFilter捕获到,发现是拒绝访问异常并且是未登录的,就会重定向到的登录页面127.0.0.1:8080/login(GET)

2.访问127.0.0.1:8080/login(GET)接口时,会被DefaultLoginPageGeneratingFilter拦截器拦截,然后返回登录页面;

3.在登录页面中输入登录信息,点击登录按钮会提交到登录接口127.0.0.1:8080/login(POST),然后会被UsernamePasswordAuthenticationFilter拦截到进行用户登录认证,认证成功后会存储用户登录信息,然后重定向到127.0.0.1:8080/test/auth(GET),此时就可以顺利通过过滤器链进入执行controller。如果认证失败就一直返回登录页面进行登录知道认证成功。

4.若想登出,直接访问127.0.0.1:8080/logout(GET),会被DefaultLogoutPageGeneratingFilter拦截到,然后会提示你是否想要登出,点击确定调用127.0.0.1:8080/logout(POST),被LogoutFilter拦截到会清除session信息,就可以退出重新登录了。

B3.动图操作

A2.上述逻辑的代码分析

B1.SecurityFilterChain的配置逻辑

使用没问题,现在看一下配置逻辑!

使用逻辑中涉及到了这几个资源:

1.端点:127.0.0.1:8080/test/auth(GET)

       2. 过滤器:FilterSecurityInterceptor         

        3.过滤器:ExceptionTranslationFilter 

4.端点:127.0.0.1:8080/login(GET)

        5.过滤器:DefaultLoginPageGeneratingFilter

6.端点:127.0.0.1:8080/login(POST) 

        7.过滤器:UsernamePasswordAuthenticationFilter

8.端点:127.0.0.1:8080/logout(GET)

       9. 过滤器:DefaultLogoutPageGeneratingFilter

10.端点:127.0.0.1:8080/logout(POST)

        11.过滤器:LogoutFilter

除去第一个端点(或者叫路径)外,其余的端点我们都没有配置,那么就跟过滤器有关,进入过滤器之后发现确实是在过滤器中设置了拦截端点,所以先了解过滤器是怎样配置的。

过滤器SecurityFilterChain是配置到过滤器链里面的,而过滤器链是HttpSecurity进行build创建的,也就是上方代码里的逻辑,return http.build();

所以重点就在 http.build() 里面,这儿就不描述的太深了,说一下大概就是:

HttpSecurity里面有filters【List】configurers【Map】属性,configurers里面存放所有的配置对象【顶级父类都是SecurityConfigurer,并且必须实现init()configure()方法】,每个配置对象里面分别会创建不同功能的filter【可能不会创建,也可能会创建多个filter】。向HttpSecurity添加完configurers之后,会执行http.build()。

执行http.build()时会先逐个调用configurersinit()方法,进行初始化【有可能会创建filter,也有可能不会,若创建filter有可能会添加到HttpSecurityfilters中,也有可能不会】,调用完毕后再逐个调用configurersconfigure()方法【有可能会创建filter,也有可能不会,若创建filter有可能会添加到HttpSecurityfilters中,也有可能不会】,之后就拿到了所有的filters的对象,最终通过performBuild(),将这写filters添加到SecurityFilterChain里面,过滤器链的过滤器就是这样创建的!

所以重点就看filter都是哪一个Configurer创建的?都是怎样创建的?是否有关联逻辑?

C1.filter对应的Configurer

通过debug能看到在build过滤器链之前,httpsecurity里面就已经有configurers了 (如果我们没有自己创建HttpSecurity对象,就会使用系统提供的,可以看HttpSecurityConfiguration#httpSecurity()方法)

所以这10个configurers就是系统创建HttpSecurity对象后默认添加进去的,重点在方法里面的这两行代码,除去第二个.addFilter,其余的10个方法都是添加configurers :

http
.csrf(Customizer.withDefaults())
.addFilter(new WebAsyncManagerIntegrationFilter())
.exceptionHandling(Customizer.withDefaults())
.headers(Customizer.withDefaults())
.sessionManagement(Customizer.withDefaults())
.securityContext(Customizer.withDefaults())
.requestCache(Customizer.withDefaults())
.anonymous(Customizer.withDefaults())
.servletApi(Customizer.withDefaults())
.apply(new DefaultLoginPageConfigurer());

http.logout(Customizer.withDefaults());

/*
可以任意点击一个方法进去查看,可以看到里面都会调用这个方法:this.getOrApply(Configurer对象),
这个方法的逻辑就是将会添加到configurers里面
*/

/*
而Customizer.withDefaults(),可以理解为调用对象的构造器创建对象,而根据哪个类创建对象呢?
就可以点击当前调用的方法进入查看入参的类型,就能确定创建的是什么对象。

例如:点击http.logout()方法,进入后发现是
public HttpSecurity logout(Customizer<LogoutConfigurer<HttpSecurity>> logoutCustomizer){}
那么就是会创建LogoutConfigurer对象~

而这行代码也相等于下面的这个,里面的参数 t 就是 LogoutConfigurer 类型的对象~~~
http.logout(t -> {});

*/

而在创建过滤链之前,又会通过添加两个configurer: 

最终可以通过类的名字分析出跟登录相关的有:

1.ExceptionHandlingConfigurer   --->  ExceptionTranslationFilter

2.DefaultLoginPageConfigurer   --->  DefaultLoginPageGeneratingFilter + DefaultLogoutPageGeneratingFilter

3.LogoutConfigurer   ---> LogoutFilter

4.ExpressionUrlAuthorizationConfigurer   --->  FilterSecurityInterceptor

5.FormLoginConfigurer   --->  UsernamePasswordAuthenticationFilter

C2.ExceptionHandlingConfigurer   --->  ExceptionTranslationFilter

ExceptionTranslationFilter 过滤器主要功能是捕获跟认证相关的异常并处理,捕获这一块儿我们不用操心,但我们可以自定义异常处理类,只需要自定义两个类并分别实现AccessDeniedHandler(用来解决认证过的用户访问无权限资源时的异常)、AuthenticationEntryPoint(用来解决匿名用户访问无权限资源时的异常),然后添加到filter里就行,还是通过对应的configurers进行添加;

那么反观 ExceptionHandlingConfigurer  类,能看到重点在他的 configure() 方法里面,在这个方法里面他自己创建了两个处理类,并添加到filter里面,然后又添加到httpsecurity的filter里面。

--------- ExceptionHandlingConfigurer 
   public void configure(H http) {
        AuthenticationEntryPoint entryPoint = this.getAuthenticationEntryPoint(http);
        ExceptionTranslationFilter exceptionTranslationFilter = new ExceptionTranslationFilter(entryPoint, this.getRequestCache(http));
        AccessDeniedHandler deniedHandler = this.getAccessDeniedHandler(http);
        exceptionTranslationFilter.setAccessDeniedHandler(deniedHandler);
        exceptionTranslationFilter = (ExceptionTranslationFilter)this.postProcess(exceptionTranslationFilter);
        http.addFilter(exceptionTranslationFilter);
    }
// 可以通过这样的方式,设置自定义处理器,handler类自定义即可

    @Bean
    SecurityFilterChain defaultSecurityFilterChain1(HttpSecurity http) throws Exception {

        //方式1
        http.exceptionHandling(exceptionHandlingConfigurer -> {
            exceptionHandlingConfigurer.accessDeniedHandler(new AccessDeniedHandlerImpl());
            exceptionHandlingConfigurer.authenticationEntryPoint(new Http403ForbiddenEntryPoint());
        });
        //方式2
        http.exceptionHandling()
                .accessDeniedHandler(new AccessDeniedHandlerImpl())
                .authenticationEntryPoint(new Http403ForbiddenEntryPoint());
        
        return http.build();
    }

C3.DefaultLoginPageConfigurer   --->  DefaultLoginPageGeneratingFilter + DefaultLogoutPageGeneratingFilter

DefaultLoginPageGeneratingFilter + DefaultLogoutPageGeneratingFilter 这两个过滤器主要功能分别是生成登录页面和登出页面并返回。这两个过滤器就挺简单的,看源代码的逻辑就知道,默认的登录、登出路径分别是"/login","/logout",并且都得是GET请求类型,最终返回的都是contentType都是"text/html;charset=UTF-8"类型的。

而看DefaultLoginPageConfigurer  ,这个对象在创建的时候就直接new了这两个过滤器,对于Login来说只是单纯的new了这个过滤器对象,他里面的属性都是空的,例如各种url啊等等,也就是这个过滤器还没什么作用!Logout是有设置拦截路径等属性的。

所以configurer他的主要的业务逻辑也在configure() 方法里面。


但是要注意,在执行他的configure() 前,一定会先执行 FormLoginConfigurer#init(H http)【这个逻辑在之前有说过哦~】,而这个init()方法里面,会调用FormLoginConfigurer# initDefaultLoginFilter(H http),这个方法会根据FormLoginConfigurer#customLoginPage(它父类的类属性)属性 T/F 来判断是否向DefaultLoginPageGeneratingFilter过滤器添加属性,也就是说DefaultLoginPageGeneratingFilter过滤器是否能使用跟FormLoginConfigurer有关系!

然后我们再看FormLoginConfigurer#customLoginPage属性是怎么变化的,这个类属性默认没有值那就是false,然后只有一个地方赋值了,是在 FormLoginConfigurer#loginPage() ,方法里面赋值为 true,并且没有地方能够在修改它!

所以最终得出结论,如果我们更改了FormLoginConfigurer的拦截路径,就无法使用默认的登录表单:

1.如果仅调用http.formLogin() ,那么DefaultLoginPageGeneratingFilter过滤器就可以使用;

2.如果调用http.formLogin() .loginPage("拦截路径"),那么DefaultLoginPageGeneratingFilter过滤器就不能再使用;


 再返回来说他的DefaultLoginPageConfigurer#configure() 方法,这个方法里面最重要的一个逻辑就是 this.loginPageGeneratingFilter.isEnabled() == true 那么就将这两个过滤器添加到httpsecurity的filters里面~

----------FormLoginConfigurer
public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractAuthenticationFilterConfigurer<H, FormLoginConfigurer<H>, UsernamePasswordAuthenticationFilter> {

    public void init(H http) throws Exception {
        super.init(http);
        this.initDefaultLoginFilter(http);
    }

    private void initDefaultLoginFilter(H http) {
        DefaultLoginPageGeneratingFilter loginPageGeneratingFilter = (DefaultLoginPageGeneratingFilter)http.getSharedObject(DefaultLoginPageGeneratingFilter.class);
        if (loginPageGeneratingFilter != null && !this.isCustomLoginPage()) {
            loginPageGeneratingFilter.setFormLoginEnabled(true);
            loginPageGeneratingFilter.setUsernameParameter(this.getUsernameParameter());
            loginPageGeneratingFilter.setPasswordParameter(this.getPasswordParameter());
            loginPageGeneratingFilter.setLoginPageUrl(this.getLoginPage());
            loginPageGeneratingFilter.setFailureUrl(this.getFailureUrl());
            loginPageGeneratingFilter.setAuthenticationUrl(this.getLoginProcessingUrl());
        }

    }

}


------------AbstractAuthenticationFilterConfigurer
public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecurityBuilder<B>, T extends AbstractAuthenticationFilterConfigurer<B, T, F>, F extends AbstractAuthenticationProcessingFilter> extends AbstractHttpConfigurer<T, B> {
    private String loginPage;

    public final boolean isCustomLoginPage() {
        return this.customLoginPage;
    }
}


------------DefaultLoginPageConfigurer
public final class DefaultLoginPageConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHttpConfigurer<DefaultLoginPageConfigurer<H>, H> {
    private DefaultLoginPageGeneratingFilter loginPageGeneratingFilter = new DefaultLoginPageGeneratingFilter();
    private DefaultLogoutPageGeneratingFilter logoutPageGeneratingFilter = new DefaultLogoutPageGeneratingFilter();

    public void configure(H http) {
        AuthenticationEntryPoint authenticationEntryPoint = null;
        ExceptionHandlingConfigurer<?> exceptionConf = (ExceptionHandlingConfigurer)http.getConfigurer(ExceptionHandlingConfigurer.class);
        if (exceptionConf != null) {
            authenticationEntryPoint = exceptionConf.getAuthenticationEntryPoint();
        }

        if (this.loginPageGeneratingFilter.isEnabled() && authenticationEntryPoint == null) {
            this.loginPageGeneratingFilter = (DefaultLoginPageGeneratingFilter)this.postProcess(this.loginPageGeneratingFilter);
            http.addFilter(this.loginPageGeneratingFilter);
            LogoutConfigurer<H> logoutConfigurer = (LogoutConfigurer)http.getConfigurer(LogoutConfigurer.class);
            if (logoutConfigurer != null) {
                http.addFilter(this.logoutPageGeneratingFilter);
            }
        }

    }
}

C4.LogoutConfigurer   ---> LogoutFilter

LogoutFilter 过滤器主要功能是拦截登出请求(默认是"/logout"),然后执行登出操作,完成登录后执行登出成功处理。看源码就能理解大致逻辑啦。记住这个请求是处理登陆操作,不是生成登出确认页面哦!我们同样可以自定义登出请求路径、登出操作处理、登出成功操作处理,这些配置还是通过configurer来设置的。

而看LogoutConfigurer   ,这个对象主要的逻辑也在 configure() 方法里面,直接创建一个LogoutFilter对象,这个对象的主要属性RequestMatcher、LogoutHandler、LogoutSuccessHandler都是在这儿添加的,而这里添加时会判断是否有自定义的,有就拿自定义的,没有就创建默认的。

----------LogoutConfigurer
public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHttpConfigurer<LogoutConfigurer<H>, H> {
    public void configure(H http) throws Exception {
        LogoutFilter logoutFilter = this.createLogoutFilter(http);
        http.addFilter(logoutFilter);
    }

    private LogoutFilter createLogoutFilter(H http) {
        this.logoutHandlers.add(this.contextLogoutHandler);
        this.logoutHandlers.add((LogoutHandler)this.postProcess(new LogoutSuccessEventPublishingLogoutHandler()));
        LogoutHandler[] handlers = (LogoutHandler[])this.logoutHandlers.toArray(new LogoutHandler[0]);
        //先添加两个处理器
        LogoutFilter result = new LogoutFilter(this.getLogoutSuccessHandler(), handlers);
        //然后添加拦截路径
        result.setLogoutRequestMatcher(this.getLogoutRequestMatcher(http));
        result = (LogoutFilter)this.postProcess(result);
        return result;
    }

    private RequestMatcher getLogoutRequestMatcher(H http) {
        //先判断拦截路径匹配器是否有,有就直接用
        if (this.logoutRequestMatcher != null) {
            return this.logoutRequestMatcher;
        } else {    //没有就创建
            this.logoutRequestMatcher = this.createLogoutRequestMatcher(http);
            return this.logoutRequestMatcher;
        }
    }

    private RequestMatcher createLogoutRequestMatcher(H http) {
        RequestMatcher post = this.createLogoutRequestMatcher("POST");
        if (http.getConfigurer(CsrfConfigurer.class) != null) {
            return post;
        } else {
            RequestMatcher get = this.createLogoutRequestMatcher("GET");
            RequestMatcher put = this.createLogoutRequestMatcher("PUT");
            RequestMatcher delete = this.createLogoutRequestMatcher("DELETE");
            return new OrRequestMatcher(new RequestMatcher[]{get, post, put, delete});
        }
    }

    private RequestMatcher createLogoutRequestMatcher(String httpMethod) {
        //最终的创建也就拿 logoutUrl 创建~
        return new AntPathRequestMatcher(this.logoutUrl, httpMethod);
    }
}
// 可以通过这样的方式,设置自定义处理器,handler类自定义即可

    @Bean
    SecurityFilterChain defaultSecurityFilterChain1(HttpSecurity http) throws Exception {

        //方式1
        http.logout(httpSecurityLogoutConfigurer -> {
            httpSecurityLogoutConfigurer.logoutUrl("/custom/logout");
            httpSecurityLogoutConfigurer.logoutRequestMatcher(new AntPathRequestMatcher("/matcher/custom/logout", "POST"));
            httpSecurityLogoutConfigurer.addLogoutHandler(new SecurityContextLogoutHandler());
            httpSecurityLogoutConfigurer.logoutSuccessHandler(new SimpleUrlLogoutSuccessHandler());

        });
        //方式2
        http.logout()
                .logoutUrl("/custom/logout")    //拦截路径,权重小于拦截路径匹配器,如果有拦截路径匹配器就不使用拦截路径
                .logoutRequestMatcher(new AntPathRequestMatcher("/matcher/custom/logout", "POST"))  //拦截路径匹配器,这个权重高;如果没有匹配器会将拦截路径转化成匹配器使用
                .addLogoutHandler(new SecurityContextLogoutHandler())   //这个处理器的逻辑是设置session失效的,也是默认的登出处理器
                .logoutSuccessHandler(new SimpleUrlLogoutSuccessHandler()); //这个处理器的逻辑是跳转路径的,也是默认的登出成功处理器


        
        return http.build();
    }

C6.FormLoginConfigurer   --->  UsernamePasswordAuthenticationFilter

UsernamePasswordAuthenticationFilter 过滤器主要功能是拦截登录请求(默认是"/login"),这个过滤器的核心不是拦截,而是拿到登录用户信息(默认只拿取用户名和密码,并且必须按照指定的参数名传值),并判断是否能够认证登录。拦截的业务是交给他的父类来操作的。注意不是获取登录页面哦~

通过代码逻辑可以看到,UsernamePasswordAuthenticationFilter 构造时本来就提供了DEFAULT_ANT_PATH_REQUEST_MATCHER,并且是没有修改该属性的方法的!最终这个属性会被new成父类里面的RequestMatcher类型的对象,RequestMatcher类型的对象是有修改方法的,但是我们又无法使用~

而我们能够自定义请求提交参数的参数名,例如filter里面有usernameParameter和passwordParameter属性,这来各个分别对应用户名和密码,我们可以修改这两个参数名。修改后过滤器会从请求中拿到对应参数名的传值,然后通过usernameParameter从持久层中拿到用户对象,拿不到就抛异常,拿得到就将passwordParameter与拿到的用户密码进行比较,匹配上就登陆成功,匹配不上就抛异常~

也能定义登录成功或者失败后跳转的路径和对应的处理器。

而看FormLoginConfigurer  ,他的 init() 方法作用我们在C3里就说过了,他的另一个核心方法就是 configure() ,而这个方法FormLoginConfigurer  是没有实现的,执行的是它的父类AbstractAuthenticationFilterConfigurer的 configure() 方法。

进入 configure() 方法后,能看到里面并没有创建UsernamePasswordAuthenticationFilter 对象,其实是在构建FormLoginConfigurer对象时new的。  configure() 方法只往filter里面设置属性。具体的看源码~

---------FormLoginConfigurer
public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractAuthenticationFilterConfigurer<H, FormLoginConfigurer<H>, UsernamePasswordAuthenticationFilter> {
    public FormLoginConfigurer() {
        super(new UsernamePasswordAuthenticationFilter(), (String)null);
        this.usernameParameter("username");
        this.passwordParameter("password");
    }
}


---------AbstractAuthenticationFilterConfigurer
public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecurityBuilder<B>, T extends AbstractAuthenticationFilterConfigurer<B, T, F>, F extends AbstractAuthenticationProcessingFilter> extends AbstractHttpConfigurer<T, B> {

 
}
  
// 可以通过这样的方式,设置自定义处理器,handler类自定义即可

    @Bean
    SecurityFilterChain defaultSecurityFilterChain1(HttpSecurity http) throws Exception {

        //方式1
        http.formLogin(httpSecurityFormLoginConfigurer -> {
           httpSecurityFormLoginConfigurer.loginPage("/custom/login") ;
           httpSecurityFormLoginConfigurer.passwordParameter("psw") ;
           httpSecurityFormLoginConfigurer.usernameParameter("usn") ;
           httpSecurityFormLoginConfigurer.loginProcessingUrl("/custom/loginaction") ;
           httpSecurityFormLoginConfigurer.successForwardUrl("/custom/loginsuccess") ;
           httpSecurityFormLoginConfigurer.failureForwardUrl("/custom/loginfail") ;
           httpSecurityFormLoginConfigurer.successHandler(new SimpleUrlAuthenticationSuccessHandler()) ;
           httpSecurityFormLoginConfigurer.failureHandler(new SimpleUrlAuthenticationFailureHandler()) ;
        });

        //方式2
        http.formLogin()
                .loginPage("/custom/login") //自定义登录页面的访问路径,一旦设置了,就只能使用自定义的登录页面,不能再使用DefaultLoginPageGeneratingFilter 过滤器创建的哦~
                .passwordParameter("psw") //可以自定义密码参数的参数名
                .usernameParameter("usn") //可以自定义用户名参数的参数名
                .loginProcessingUrl("/custom/loginaction") //使用UsernamePasswordAuthenticationFilter过滤器的情况下,自定义其登录请求的路径;(如果自定义拦截器需要实现这个逻辑哦~)
                .successForwardUrl("/custom/loginsuccess") //自定义登陆成功后跳转路径
                .failureForwardUrl("/custom/loginfail") //自定义登陆失败后跳转路径
                .successHandler(new SimpleUrlAuthenticationSuccessHandler())    //自定义登陆成功后的处理器
                .failureHandler(new SimpleUrlAuthenticationFailureHandler());   //自定义登陆失败后的处理器


        
        return http.build();
    }

A3.总结

B1.默认的表单登录逻辑

默认提供的表单登录页面和登录认证请求,都是有局限性的,本来就是提供的简单的实现方式,而且是前后端不分离的。

我们可以进行自定义的,例如仅使用默认的用户名密码登陆的模式下(即使用UsernamePasswordAuthenticationFilter过滤器),可以修改成前后端分离的模式,登录认证请求action由后端完成,登录页面由前端完成。这时只要增加一个登录页面,并且设置自定义登录页面路径,然后在登录页面里修改用户名、密码标签的name为我们指定的,然后表单提交路径也为我们置顶就可以啦。

如果我们还想要实现手机号码登录或者邮箱登录,就需要自定义拦截器逻辑~

注意:登录认证拦截器的核心是AuthenticationManager,我们想自定义登录认证拦截器还要考虑AuthenticationManager哒!


B2.DefaultLoginPageConfigurer 、FormLoginConfigurer的区别

DefaultLoginPageConfigurer专注于生成登录/登出页面,FormLoginConfigurer专注于登录认证操作。

如果我们完全使用默认的FormLoginConfigurer配置方式,就可以使用DefaultLoginPageConfigurer配置的过滤器的登录登出页面,如果我们给FormLoginConfigurer设置了指定登陆页面,就不能再使用到DefaultLoginPageConfigurer配置的过滤器的登录登出页面


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值