【问题标题】:how to store user details in session and pass to Spring REST controllers如何在会话中存储用户详细信息并传递给 Spring REST 控制器
【发布时间】:2020-07-20 13:37:33
【问题描述】:

我们有登录页面,用户将在其中输入用户凭据并在内部调用一个需要存储此令牌并传递给所有 REST 控制器的身份验证服务。我尝试在此类中配置 bean 范围,但低于异常。我们正在使用春天 5.x;

com.config.CustomAuthenticationProvider sessionScopedBean CustomAuthenticationProvider 用户详细信息 !!!null 2020 年 6 月 20 日上午 11:52:37 org.apache.catalina.core.StandardWrapperValve 调用

java.lang.ClassCastException: org.springframework.beans.factory.support.NullBean 无法转换为 com.utils.UserDetails

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

    private Logger logger = Logger.getLogger(getClass().getName());
    private UserDetails userDetails;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String userName = authentication.getName();
        String passWord = authentication.getCredentials().toString();

        Result response;
        try {
            response = CustomClient.authenticate(userName, passWord);
        } catch (Exception e) {
            throw new BadCredentialsException("system authentication failed");
        }
        if (response != null && response.getToken() != null) {

            //need to store this response.getToken() in session
            logger.info("Token: " + response.getToken());

            userDetails= new UserDetails();
                userDetails.setToken(response.getToken());


            logger.info("Authentication SUCCESS !!!");
            return new UsernamePasswordAuthenticationToken(userName, passWord, Collections.emptyList());
        } else {
            logger.info("Authentication FAILED...");
            throw new BadCredentialsException("authentication failed");
        }
    }

   @Bean
    @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public UserDetails sessionScopedBean() {
        logger.info(" UserDetails !!!"+userDetails);
        return userDetails;
    }

    @Override
    public boolean supports(Class<?> auth) {
        return auth.equals(UsernamePasswordAuthenticationToken.class);
    }
}

【问题讨论】:

    标签: spring spring-mvc spring-security


    【解决方案1】:

    为什么首先要创建会话范围UserDetails bean?您已经可以通过执行以下操作来实现它:

    @GetMapping("/abc")
    public void getUserProfile(@AuthenticationPrincipal UserDetails user ) {
    ...
    }
    

        @GetMapping("/abc")
        public void getUserProfile() {
            SecurityContext securityContext = SecurityContextHolder.getContext();
            UserDetails user = (UserDetails) securityContext.getAuthentication().getPrincipal();
        }
    

    注意:

    在幕后,spring 使用 HttpSessionSecurityContextRepository 将您的 SecurityContext 存储在 http 会话中,并在每次请求时恢复它

    以及更新后的 CustomAuthenticationProvider

    @Component
    public class CustomAuthenticationProvider implements AuthenticationProvider {
    
        private Logger logger = Logger.getLogger(getClass().getName());
    
        @Override
        public Authentication authenticate(Authentication authentication) throws AuthenticationException {
            String userName = authentication.getName();
            String passWord = authentication.getCredentials().toString();
    
            Result response;
            try {
                response = CustomClient.authenticate(userName, passWord);
            } catch (Exception e) {
                throw new BadCredentialsException("system authentication failed");
            }
            if (response != null && response.getToken() != null) {
    
                //need to store this response.getToken() in session
                logger.info("Token: " + response.getToken());
    
                UserDetails userDetails= new UserDetails();
                userDetails.setToken(response.getToken());
    
    
                logger.info("Authentication SUCCESS !!!");
                return new UsernamePasswordAuthenticationToken(userDetails, passWord, Collections.emptyList());
            } else {
                logger.info("Authentication FAILED...");
                throw new BadCredentialsException("authentication failed");
            }
        }
    
        @Override
        public boolean supports(Class<?> auth) {
            return auth.equals(UsernamePasswordAuthenticationToken.class);
        }
    }
    

    【讨论】:

      【解决方案2】:

      首先你不能像你的例子那样创建 Bean。 @Bean 注解在应用程序上下文启动时进行处理。 UserDetails 将为 null,因此无法创建。

      应用上下文启动后,您正在创建 UserDetails。

      如果是这样,你真的要保持会话吗

      @Configuration
      public class Config {
      
          @Bean
          @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
          public UserDetails userDetails() {
              return new UserDetails();
          }
      
      }
      
      
      @Component
      public class CustomAuthenticationProvider implements AuthenticationProvider {
      
          private Logger logger = Logger.getLogger(getClass().getName());
          @Autowired
          private UserDetails userDetails;
          
      }
      

      你可以通过 Autowire 或构造函数注入来注入

      不要手动实例化它,只需注入它并在下面的方法中使用

      userDetails.setToken(response.getToken());
      

      【讨论】:

      • SpringSecurityContextHolder 为你保留数据,如果你想接收它
      猜你喜欢
      • 1970-01-01
      • 2018-08-28
      • 2017-12-29
      • 1970-01-01
      • 2014-03-16
      • 2016-11-24
      • 1970-01-01
      • 2020-01-31
      • 2021-11-05
      相关资源
      最近更新 更多