spring security 配置successHandler无效,仍跳转默认路径

spring security自定义配置类继承WebSecurityConfigurerAdapter,一般会配置开放接口、登录接口以及自定义的过滤器等

// 这里我配置了登录成功后返回json数据,但并没有效果,仍然跳转到默认路径/
http
     .formLogin()
     .successHandler(
	     (request, response, authentication) -> {
	            CustomUser principal = (CustomUser) authentication.getPrincipal();
	            response.setCharacterEncoding("utf-8");
	            response.setContentType("application/json;charset=utf-8");
	            PrintWriter out = response.getWriter();
	            out.write(JSON.toJSONString(ResultVo.SUCCESS(JwtUtils.generateJsonWebToken(principal))));
	            out.flush();
	            out.close();
	        }
		)

走进successHandler()方法看到,该方法位于AbstractAuthenticationFilterConfigurer类中

public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecurityBuilder<B>, T extends AbstractAuthenticationFilterConfigurer<B, T, F>, F extends AbstractAuthenticationProcessingFilter> extends AbstractHttpConfigurer<T, B> {
    private F authFilter;
    private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource;
    private SavedRequestAwareAuthenticationSuccessHandler defaultSuccessHandler;
    private AuthenticationSuccessHandler successHandler;
    private LoginUrlAuthenticationEntryPoint authenticationEntryPoint;
    private boolean customLoginPage;
    private String loginPage;
    private String loginProcessingUrl;
    private AuthenticationFailureHandler failureHandler;
    private boolean permitAll;
    private String failureUrl;

    protected AbstractAuthenticationFilterConfigurer() {
    // 这里面定义了默认的登录成功处理SavedRequestAwareAuthenticationSuccessHandler
        this.defaultSuccessHandler = new SavedRequestAwareAuthenticationSuccessHandler();
        this.successHandler = this.defaultSuccessHandler;
        this.setLoginPage("/login");
    }

    public final T defaultSuccessUrl(String defaultSuccessUrl) {
        return this.defaultSuccessUrl(defaultSuccessUrl, false);
    }

    public final T defaultSuccessUrl(String defaultSuccessUrl, boolean alwaysUse) {
        SavedRequestAwareAuthenticationSuccessHandler handler = new SavedRequestAwareAuthenticationSuccessHandler();
        handler.setDefaultTargetUrl(defaultSuccessUrl);
        handler.setAlwaysUseDefaultTargetUrl(alwaysUse);
        this.defaultSuccessHandler = handler;
        return this.successHandler(handler);
    }

   ...

	// 自定义成功处理调用这个方法,都是设置successHandler
    public final T successHandler(AuthenticationSuccessHandler successHandler) {
        this.successHandler = successHandler;
        return this.getSelf();
    }

}

可以看出这个类是认证过滤器配置类,因为我后面还配置了自定义的登录过滤器,所有会不会是后面配置的过滤器把上面的配置覆盖掉了

public class AuthenticationProcessingFilter extends UsernamePasswordAuthenticationFilter {

    /**
     * json格式登录
     * @param request
     * @param response
     * @return
     * @throws AuthenticationException
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)) {
            ObjectMapper mapper = new ObjectMapper();
            UsernamePasswordAuthenticationToken authRequest = null;
            try (InputStream is = request.getInputStream()) {
                Map<String, String> authenticationBean = mapper.readValue(is, Map.class);
                authRequest = new UsernamePasswordAuthenticationToken(authenticationBean.get("username"), authenticationBean.get("password"));
            } catch (IOException e) {
                e.printStackTrace();
                authRequest = new UsernamePasswordAuthenticationToken("", "");
            }
            setDetails(request, authRequest);
            return this.getAuthenticationManager().authenticate(authRequest);
        } else {
            return super.attemptAuthentication(request, response);
        }
    }

}

这里继承UsernamePasswordAuthenticationFilter ,重写的认证方法,走进UsernamePasswordAuthenticationFilter 发现他继承AbstractAuthenticationProcessingFilter

public abstract class AbstractAuthenticationProcessingFilter extends GenericFilterBean implements ApplicationEventPublisherAware, MessageSourceAware {
    protected ApplicationEventPublisher eventPublisher;
    protected AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
    private AuthenticationManager authenticationManager;
    protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
    private RememberMeServices rememberMeServices = new NullRememberMeServices();
    private RequestMatcher requiresAuthenticationRequestMatcher;
    private boolean continueChainBeforeSuccessfulAuthentication = false;
    private SessionAuthenticationStrategy sessionStrategy = new NullAuthenticatedSessionStrategy();
    private boolean allowSessionCreation = true;

	// 他里面也定义的这个SavedRequestAwareAuthenticationSuccessHandler
	// 我上面配置的SuccessHandler没有生效,可能是他走的是这个
    private AuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
    private AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();

	...

	// 这里面也有一个设置SuccessHandler的方法
    public void setAuthenticationSuccessHandler(AuthenticationSuccessHandler successHandler) {
        Assert.notNull(successHandler, "successHandler cannot be null");
        this.successHandler = successHandler;
    }
}

然后我就在配置类中添加过滤器的地方设置successHandler

	@Bean
    public AuthenticationProcessingFilter authenticationProcessingFilter() throws Exception {
        AuthenticationProcessingFilter authenticationProcessingFilter = new AuthenticationProcessingFilter();
        authenticationProcessingFilter.setAuthenticationManager(authenticationManagerBean());
        // 设置successHandler 
        authenticationProcessingFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler());
        return authenticationProcessingFilter;
    }
    
	@Override
    protected void configure(AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(adminAuthenticationProvider());
    }

    /**
     * 自定义认证
     * @return
     */
    @Bean
    public AdminAuthenticationProvider adminAuthenticationProvider() {
        return new AdminAuthenticationProvider();
    }

@Bean
    public AuthenticationSuccessHandler authenticationSuccessHandler() {
        return (request, response, authentication) -> {
            CustomUser principal = (CustomUser) authentication.getPrincipal();
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/json;charset=utf-8");
            PrintWriter out = response.getWriter();
            out.write(JSON.toJSONString(ResultVo.SUCCESS(JwtUtils.generateJsonWebToken(principal))));
            out.flush();
            out.close();
        };
    }

这样设置就可以了。总结:当添加过滤器时,在过滤器中设置AuthenticationSuccessHandler,而不要在http.formLogin()后面设置

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用以下配置跳转到指定的页面: 在 Spring Security 配置中,使用`formLogin()`方法开启表单登录,在其中设置`loginPage()`方法来指定登录页面地址,如下所示: ```java @Configuration @EnableWebSecurity public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/public/**").permitAll() // 不进行权限验证的 URL .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") // 指定登录页面地址 .permitAll() .and() .logout() .permitAll(); } } ``` 在上述代码中,`/login` 路径为登录页面地址,是一个 GET 请求,访问该路径时返回登录页面。在登录页面中,用户输入用户名和密码,然后提交表单,将会通过 POST 请求发送到`/login`地址。 通过重写 `configure(AuthenticationManagerBuilder auth)` 方法,可以指定用户认证方式默认使用内存中的认证方式。在下面的代码示例中,使用了一对用户名和密码 `user/userpassword`。 ```java @Configuration @EnableWebSecurity public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/public/**").permitAll() // 不进行权限验证的 URL .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") // 指定登录页面地址 .permitAll() .and() .logout() .permitAll(); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth .inMemoryAuthentication() .withUser("user") .password("{noop}userpassword") .roles("USER"); } } ``` 在上述代码中,“{noop}” 是 5.x 版本的特性,用于指定密码以明文形式存储。否则的话,需要使用`PasswordEncoder`接口的实现来加密密码,不过这样做对于一个小型项目并不是必要的。 Spring Security 提供了默认的 login form 表单,不过在以下情况下,可能需要重写默认的登录页面模板。 默认模板位于`/org/springframework/security/web/server/ui/login/LoginPageGeneratingWebFilter.DEFAULT_LOGIN_PAGE_TEMPLATE`。 利用 FreeMarker 模板引擎可以重写该模板。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值