java 如何在Spring Security中通过会话进行身份验证?

ws51t4hk  于 2023-02-07  发布在  Java
关注(0)|答案(1)|浏览(131)

所以我有一个Angular前端应用程序和一个Spring后端应用程序。目前,我的应用程序上似乎有一个JSessionId的cookie(我只在登录时收到,而不是在注册时收到,无论出于什么原因)(cookies)
我假设它会将这些cookie发送回服务器。(尽管这只是一个假设)
现在,当我向受保护的服务器发出请求时,得到的唯一结果是弹出“请登录”。Login popup
当我登录时,我的UserService记录了一个用户,其中包含以下详细信息:

UsernamePasswordAuthenticationToken [Principal=User(userId=1, name=Maksym Riabov, username=MRiabov, password={bcrypt}$2a$10$W0XJRQdfxV5XXORkr2bTluIHvFetIVBzmVp51l39T5zLCQk12RV1i, company=null, enabled=true), Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[ADMIN]]

我注意到这里的sessionId是空的,为什么会这样呢?
为了回答前面的一些问题:

  • 是的,我已粘贴{withCredentials:true}到每个请求。(特定于Angular )
  • 是的,我读过文档--我甚至试着从它那里粘贴所有的代码,看起来它不起作用。

我的登录控制器:

@GetMapping("/login")
    public ResponseEntity<String> login() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        return ResponseEntity.ok("123123");
    }

    @PostMapping("/register")
    public ResponseEntity<Map<String, String>> register(@RequestBody UserRegisterDto userDto) {
        //todo check if name taken
        User user = userMapper.toEntity2(userDto);
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        user.setEnabled(true);
        //todo remove
        Authority authority = authorityRepository.save(new Authority("ADMIN"));
        user.setAuthorities(Set.of(authority));
        //todo REMOVE!!!!

        User savedUser = userRepository.save(user);
        System.out.println("registration works!");

        return ResponseEntity.ok(Map.of("result",authority.getAuthority().getAuthority()));
    }

现在,我发送一个请求到后端(它把弹出窗口以上),像这样:

@PreAuthorize("hasRole('ADMIN')")
    @GetMapping("/create")
    public ResponseEntity<OnboardingPathDto> createOnboardingPath() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        // erased a bit of code here
        return ResponseEntity.ok().build();

如您所见,我有一个方法安全性,它抛出auth请求。
最上面的樱桃

@Component
@EnableWebSecurity
@EnableMethodSecurity(securedEnabled = true, jsr250Enabled = true)
@RequiredArgsConstructor
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http, UserDetailsService userDetailsService) throws Exception {
        http
                .csrf().disable().cors().disable()
                .authorizeHttpRequests() 
                .anyRequest().permitAll() //todo this is unsafe
                .and().sessionManagement(session -> session.
                        sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
                        .maximumSessions(1))//to force only one session per user
     //here I tried sessionManagement to do something, but did it do something?
                .rememberMe((rememberMe) -> rememberMe.userDetailsService(userDetailsService))
                .httpBasic(); 
        return http.build();
    }

    @Bean
    public AuthenticationManager authenticationManager(DaoAuthenticationProvider daoAuthenticationProvider) throws Exception {
        return new ProviderManager(daoAuthenticationProvider);
    }

    @Bean
    public DaoAuthenticationProvider prov(PasswordEncoder passwordEncoder, UserDetailsService userDetailService) throws Exception {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setPasswordEncoder(passwordEncoder);
        daoAuthenticationProvider.setUserDetailsService(userDetailService);
        return daoAuthenticationProvider;
    }
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

    @Bean
    public HttpSessionEventPublisher httpSessionEventPublisher() {//to force only one session per user
        return new HttpSessionEventPublisher();
    }

我已经广泛地阅读了Spring Security文档,甚至还参加了一门关于它的课程,但我仍然无法使它工作。
所以,我在纠结的是:

  • ###为什么Spring不能通过会话进行身份验证,即使它被配置为这样做?我的错误在哪里?

编辑:我假设将会话直接发送到Angular(在REST中,而不是在cookie中)确实不安全,对吗?我目前依赖cookie。
编辑2:ffs,我受够了,我只想做oauth2认证。

lf5gs5x2

lf5gs5x21#

编辑:我假设将会话直接发送到Angular(在REST中,而不是在cookie中)确实不安全,对吗?我目前依赖cookie。
你说得对,这是个坏主意。对于在浏览器中运行的应用程序中的会话,只使用带有这两个标记的cookie(值= true):

  • secure(仅通过https交换)
  • http-only(在Javascript中隐藏)。

这意味着Angular代码不应访问cookie,而是在向后端发送请求之前由浏览器自动设置cookie。
您还应该实现CSRF保护(这是spring-security中的默认设置)。
编辑2:ffs,我受够了,我只想做oauth2认证。
好主意。这对安全性、用户体验(SSO)和开发者体验都有好处:大多数OIDC提供商,无论是在内部部署(如Keycloak)还是在云中(如Auth0、Cognito等),都已经提供了登录表单(包括MultiFactorA身份验证)、用户注册、配置文件编辑、管理屏幕(如客户端声明、用户角色分配等)。

  • 我将SpringRESTAPI配置为资源服务器。我已经为此there编写了教程
  • 将您的Angular应用程序配置为:
  • 我最喜欢的Angular认证库是angular-auth-oidc-client
  • BFF客户端。BackendForFrontend是一种模式,其中服务器端中间件充当唯一的OAuth2客户端,用于向浏览器隐藏令牌。这将是安全的会议(哈哈!你的魔鬼回来了;- ),则中间件(类似于具有tokenRelay过滤器的spring-cloud-gateway)将保留该会话,将令牌关联到该会话,并且在将请求转发到resource-server之前用令牌替换会话

相关问题