Как использовать аутентификацию Spring Boot с сеансом Redis

Я пытаюсь изучить Spring Boot, написав простое приложение REST, которое будет регистрировать пользователей (POST /login) и отображать информацию о текущем пользователе (GET /). Я использую Redis для сеансов.

POST /login работает так, как ожидалось: он возвращает участника и устанавливает файл cookie сеанса как в браузере, так и в Redis.

Однако последующие запросы GET / возвращают anonymousUser. Что мне не хватает?

pom.xml:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.session</groupId>
        <artifactId>spring-session-data-redis</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

application.properties:

spring.session.store-type=redis

server.servlet.session.timeout=3600s
spring.session.redis.flush-mode=on-save
spring.session.redis.namespace=spring:session

spring.redis.host=localhost
spring.redis.port=6379

IndexController.java:

@Controller
public class IndexController {

    private AuthenticationManager authenticationManager;

    IndexController(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    @GetMapping
    ResponseEntity index(HttpServletRequest request, HttpSession session) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return new ResponseEntity<>(authentication.getPrincipal(), HttpStatus.OK);
    }

    @PostMapping("/login")
    ResponseEntity login(@RequestBody LoginRequest loginRequest) {
        String username = loginRequest.getUsername();
        String password = loginRequest.getPassword();
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
        Authentication authentication = this.authenticationManager.authenticate(token);
        return new ResponseEntity<>(authentication.getPrincipal(), HttpStatus.OK);
    }
}

Config.java:

@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@EnableRedisHttpSession
@Configuration
public class Config extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomUserDetailsService userDetailsService;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.ALWAYS)
            .and()
            .csrf()
            .disable()
            .authorizeRequests()
            .anyRequest()
            .permitAll();
    }
}

person Dmitri Maltsev    schedule 03.06.2018    source источник


Ответы (1)


Оказывается, я забыл установить authentication в методе login. Это правильный код.

@PostMapping("/login")
ResponseEntity login(@RequestBody LoginRequest loginRequest) {
    String username = loginRequest.getUsername();
    String password = loginRequest.getPassword();
    UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
    Authentication authentication = this.authenticationManager.authenticate(token);
    // vvv THIS vvv
    SecurityContextHolder
        .getContext()
        .setAuthentication(authentication);
    return new ResponseEntity<>(authentication.getPrincipal(), HttpStatus.OK);
}

См. https://docs.spring.io/spring-security/site/docs/5.0.5.RELEASE/reference/htmlsingle/#what-is-authentication-in-spring-security

person Dmitri Maltsev    schedule 11.06.2018
comment
Привет. Я использую keycloak для аутентификации/авторизации и пытаюсь использовать Redis для хранения токена. Я не могу интегрировать Redis в свое приложение с весенней загрузкой. Если вы разместили этот код в общедоступном репозитории github, не могли бы вы поделиться ссылкой? Спасибо! - person noob_nerd; 16.02.2021