Spring Security如何处理UsernameNotFoundException

user5562650:

如何处理UsernameNotFoundException

在Spring Security中,当未找到用户名时,UserDetailsService实现将引发UsernameNotFoundException例如这样:

   @Override
   @Transactional
   public UserDetails loadUserByUsername(java.lang.String username) throws UsernameNotFoundException {
       logger.info("Load user by username: {}", username);
       User user = userRepository.findUserByUsername(username).orElseThrow(
                   () -> new UsernameNotFoundException("User Not Found with -> username or email: " + username));

       return UserPrinciple.build(user);
   }

我想建立一个自定义的“未找到用户的REST响应”。我应该如何捕获/处理此异常?我已经在WebSecurityConfigurerAdapter实现中实现了处理程序方法:

  private static void handleException(HttpServletRequest req, HttpServletResponse rsp, AuthenticationException e)
           throws IOException {
       PrintWriter writer = rsp.getWriter();
       writer.println(new ObjectMapper().writeValueAsString(new AuthResponse("", null, null, null, null,
               "Authentication failed.", false)));
       rsp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
   }

但是此方法应等待一个AuthenticationException异常,异常在运行时期间是异常的类型,java.lang.NullPointerException因此我无法强制转换或检索initial UsernameNotFoundException

任何意见,将不胜感激。许多问候:)。

威尔逊:

安全层位于控制器和@ControllerAdvice因此@ControllerAdvice不是一种选择,因为UsernameNotFoundException这是AuthenticationException在身份验证期间抛出的子类,从而使您的异常处理程序@ControllerAdvice无法访问。

如果要扔进控制器或控制器引用的任何其他bean内@ControllerAdviceResponseEntityExceptionHandler只能使用并且UsernameNotFoundException

这是我的建议-您AuthenticationFailureHandler将其AuthenticationFilter用于安全配置并与之配合使用。Spring Boot安全性附带约4个处理程序接口,用于处理与安全性相关的问题

  1. AccessDeniedHandler -处理诸如用户没有所需角色时的问题。
  2. AuthenticationEntryPoint -处理诸如用户尝试在没有适当身份验证元素的情况下访问资源时的问题。

  3. AuthenticationFailureHandler-处理诸如找不到用户(即UsernameNotFoundException)或身份验证提供程序内引发其他异常之类的问题。实际上,这可以处理AccessDeniedExceptionand 不能处理的其他身份验证异常AuthenticationEntryPoint

  4. AuthenticationSuccessHandler -这有助于在用户成功通过身份验证后执行重定向之类的工作。

有关所有4个接口的实现,请参见以下示例代码段。请根据自己的喜好自定义这些。

  1. AccessDeniedHandler 实施
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;

@Component
public class RestAccessDeniedHandler implements AccessDeniedHandler {

    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {

        Map<String,Object> response = new HashMap<>();
        response.put("status","34");
        response.put("message","unauthorized api access");

        //httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
        httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        OutputStream out = httpServletResponse.getOutputStream();
        ObjectMapper mapper = new ObjectMapper();
        mapper.writerWithDefaultPrettyPrinter().writeValue(out,response);
        //mapper.writeValue(out, response);

        out.flush();
    }
}
  1. AuthenticationEntryPoint 实作
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;

@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {

        Map<String,Object> response = new HashMap<>();
        response.put("status","34");
        response.put("message","unauthorized access");
        httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        OutputStream out = httpServletResponse.getOutputStream();
        ObjectMapper mapper = new ObjectMapper();
        mapper.writerWithDefaultPrettyPrinter().writeValue(out, response);
        out.flush();
    }
}
  1. AuthenticationFailureHandler 实施
package com.ibiller.webservices.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;


@Component
public class RestAuthenticationFailureHandler implements AuthenticationFailureHandler
{
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse httpServletResponse,
                                        AuthenticationException ex) throws IOException, ServletException
    {

        Map<String,Object> response = new HashMap<>();
        response.put("status","34");
        response.put("message","unauthorized access");

        httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        OutputStream out = httpServletResponse.getOutputStream();
        ObjectMapper mapper = new ObjectMapper();
        mapper.writerWithDefaultPrettyPrinter().writeValue(out, response);
        out.flush();
    }
}
  1. AuthenticationSuccessHandler 实施
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class RestSuccessHandler implements AuthenticationSuccessHandler {

    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
        Set<String> roles = 
          AuthorityUtils.authorityListToSet(authentication.getAuthorities());
        if (roles.contains("ROLE_ADMIN")) {
            //do something
        }

    }
}

这是WebSecurityConfigurerAdapter将所有内容连接在一起的扩展的安全配置

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
        prePostEnabled = true,
        securedEnabled = true,
        jsr250Enabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {


    private static final RequestMatcher PROTECTED_URLS = new OrRequestMatcher(
            new AntPathRequestMatcher("/v1/**"),new AntPathRequestMatcher("/admin/**")
    );

    AuthenticationProvider provider;

    public SecurityConfiguration(final AuthenticationProvider authenticationProvider) {
        super();
        this.provider=authenticationProvider;
    }

    @Override
    protected void configure(final AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(provider);
    }


    @Override
    public void configure(final WebSecurity webSecurity) {
        webSecurity.ignoring().antMatchers("/info/**");//url that will be ignored
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .exceptionHandling()
                .accessDeniedHandler(accessDeniedHandler())
               .authenticationEntryPoint(authenticationEntryPoint())
                .and()
                .authenticationProvider(provider)
                .addFilterBefore(authenticationFilter(), AnonymousAuthenticationFilter.class)
                .authorizeRequests()
                .antMatchers("/v1/**").hasRole("API")
                .antMatchers("/admin/**").hasAnyRole("SUPER_ADMIN","ADMIN")
                .and()
                .csrf().disable()
                .formLogin().disable()
                .httpBasic().disable()
                .logout().disable();
    }

    @Bean
      AuthenticationFilter authenticationFilter() throws Exception {
        final AuthenticationFilter filter = new AuthenticationFilter(PROTECTED_URLS);
        filter.setAuthenticationManager(authenticationManager());
        filter.setAuthenticationSuccessHandler(successHandler());
        filter.setAuthenticationFailureHandler(authenticationFailureHandler());
        return filter;
    }

    @Bean
    RestAccessDeniedHandler accessDeniedHandler() {
        return new RestAccessDeniedHandler();
    }

    @Bean
    RestAuthenticationEntryPoint authenticationEntryPoint() {
        return new RestAuthenticationEntryPoint();
    }

    @Bean
    RestAuthenticationFailureHandler authenticationFailureHandler(){
        return new RestAuthenticationFailureHandler();
    }

    @Bean
    RestSuccessHandler successHandler(){
        return new RestSuccessHandler();
    }
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

在Spring Security中成功登录后如何处理用户信息

如何处理spring集成中的错误

如何处理JSONP(Spring Framework 5.1)

Spring Boot 如何处理休眠会话?

如何处理在Spring数据JDBC软删除?

Spring Cloud Stream - 如何处理下游块?

如何处理Spring / EJB / Mockito ...代理上的内部调用?

Spring Integration Flow中如何处理FtpOutboundAdapter连接异常

Java Spring-如何处理缺少的必需请求参数

Spring Integration中如何处理嵌套事务异常

在哪里以及如何处理spring + hibernate异常?

Struts 2和Spring如何处理Struts创建的对象

这里 Spring boot 内部是如何处理 http 请求的?

如何处理Java(Spring Data)中未知类型的表列?

SCM-Spring如何处理许多版本

Spring Boot中如何处理服务的可选服务依赖?

使用Spring Kafka框架时如何处理错误/异常?

如何处理Spring Boot中超时的异步请求?

如何处理Spring集成流程的事务(Java DSL)

如何处理Spring Boot的/ error重定向?

Java Spring @Autowired 如何处理从多个接口继承的接口?

如何处理 Reactive Spring webflux 中的错误

如何处理未在Spring中映射的url

Spring Boot JPA 如何处理子表更新

如何使用Spring Security / Spring MVC处理表单登录

如何处理Spring ProviderManager中引发的Spring安全性InternalAuthenticationServiceException

如何使用Spring Security很好地处理文件上传MaxUploadSizeExceededException

如何在Spring Security和thyemeleaf中处理用户权限

如何使用Spring Boot Security允许原始HttpServletRequest处理登录