当前位置: 首页 > 面试题库 >

如何在Spring Boot应用程序中使用Spring Security和Redis获取当前已认证的用户Principal

赵锐
2023-03-14
问题内容

我想通过spring安全性和Json Web Token(JWT)保护我的服务,并通过Spring
session将登录的用户存储在redis中。因此,当用户发送登录请求时,我对用户进行身份验证并将生成的令牌发送回如下所示:

public ResponseEntity<?> createAuthenticationToken(@RequestBody JwtAuthenticationRequest authenticationRequest, Device device) throws AuthenticationException {

    // Perform the security
    final Authentication authentication = authenticationManager.authenticate(
            new UsernamePasswordAuthenticationToken(
                    authenticationRequest.getUsername(),
                    authenticationRequest.getPassword()
            )
    );
    SecurityContextHolder.getContext().setAuthentication(authentication);


    final UserDetails userDetails = userDetailsService.loadUserByUsername(authenticationRequest.getUsername());
    final String token = jwtTokenUtil.generateToken(userDetails, device);

    // Return the token
    return ResponseEntity.ok(new JwtAuthenticationResponse(token));
}

我也将该用户添加到会话(支持Redis会话)中:

HttpSession session = request.getSession(false);
    if (session != null) {
        session.setMaxInactiveInterval(30 * 600);
        JwtUser user = (JwtUser) authentication.getPrincipal();
        session.setAttribute("user", user);

    }

之后我检查Redis的,我看已经被设置为redis.But当我收到来自用户下一次尝试的用户会话成为 anonymousUser
,理想情况shouldn’t.Reason这个问题的背后,是进入JSESSIONID无效莫名其妙。

        Authentication auth = SecurityContextHolder.getContext().getAuthentication();

我看到调试屏幕主体返回anonymousUser。

我也尝试如下:

@RequestMapping(value = "/username", method = RequestMethod.GET)
@ResponseBody
public String currentUserNameSimple(HttpServletRequest request) {
    Principal principal = request.getUserPrincipal();
    return principal.getName();
}

但是principal为空。

我的redis配置:

@Configuration
@EnableRedisHttpSession 
public class RedisConfig implements BeanClassLoaderAware {

private ClassLoader loader;


@Bean(name = { "defaultRedisSerializer", "springSessionDefaultRedisSerializer" })
public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
    return new GenericJackson2JsonRedisSerializer(objectMapper());

}

@Bean
public HttpSessionStrategy httpSessionStrategy() {
        return new HeaderHttpSessionStrategy(); 
}

@Bean
JedisConnectionFactory jedisConnectionFactory() {
    JedisConnectionFactory jedisConFactory = new JedisConnectionFactory();
    jedisConFactory.setHostName("localhost");
    jedisConFactory.setPort(6379);
    return jedisConFactory;
}

ObjectMapper objectMapper() {
    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModules(SecurityJackson2Modules.getModules(this.loader));
    return mapper;
}

public void setBeanClassLoader(ClassLoader classLoader) {
    this.loader = classLoader;
}

}

Maven依赖项:

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

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-mail</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>

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

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
        <version>1.4.3.RELEASE</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->




    <!-- Password Validation -->
    <dependency>
        <groupId>org.passay</groupId>
        <artifactId>passay</artifactId>
        <version>${passay.version}</version>
    </dependency>




    <dependency>
        <groupId>org.springframework.mobile</groupId>
        <artifactId>spring-mobile-device</artifactId>
        <version>1.1.4.RELEASE</version>
    </dependency>

    <!--JWT -->
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.7.0</version>
    </dependency>

    <dependency>
        <groupId>az.com.cybernet.utilities</groupId>
        <artifactId>utilities</artifactId>
        <version>0.0.1</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>az.com.cybernet.beans</groupId>
        <artifactId>disieibeans</artifactId>
        <version>0.0.1</version>
        <scope>compile</scope>
    </dependency>



    <!-- DB dependencies -->
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>9.4-1200-jdbc41</version>
    </dependency>




    <dependency>
        <groupId>javax.el</groupId>
        <artifactId>el-api</artifactId>
        <version>2.2</version>
    </dependency>


    <dependency>
        <groupId>net.logstash.logback</groupId>
        <artifactId>logstash-logback-encoder</artifactId>
        <version>4.8</version>
    </dependency>



    <!-- REDIS -->
    <dependency>
        <groupId>org.springframework.session</groupId>
        <artifactId>spring-session-data-redis</artifactId>
        <version>2.0.0.BUILD-SNAPSHOT</version>
        <type>pom</type>
    </dependency>
        <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>2.5.1</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-core</artifactId>
        <version>4.2.0.RELEASE</version>
    </dependency>




</dependencies>

没有Redis,一切都会很好,但是有了Redis,我将无法获得当前经过身份验证的用户的主体


问题答案:

我只是将jedis客户端更改为生菜客户端,如下所示,它解决了问题:

     <dependency>
        <groupId>biz.paluch.redis</groupId>
        <artifactId>lettuce</artifactId>
        <version>3.5.0.Final</version>
    </dependency>

在Spring安全之前,Principal对象为null,因为Jedis客户端尚未创建名为“ JSESSIONID”的cookie。

@EnableRedisHttpSession
public class RedisConfig {
@Bean
public LettuceConnectionFactory connectionFactory() {
    return new LettuceConnectionFactory();
}

@Bean
public CookieSerializer cookieSerializer() {
    DefaultCookieSerializer serializer = new DefaultCookieSerializer();
    serializer.setCookieName("JSESSIONID"); // <1>
    serializer.setCookiePath("/"); // <2>
    serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$"); // <3>
    return serializer;
}
}


 类似资料:
  • 要获取请求URL,可以在堆栈溢出中找到以下方法。 第一种方法: 第二种方法: 第三种方法: 我不知道在spring boot应用程序中使用哪一个来获取请求URL。 如果我使用第三种方法,那么我是否需要在配置类中创建RequestContextListener的bean,如下所示?

  • 如何在MVC 5中获取当前登录用户的id?我尝试了StackOverflow建议,但它们似乎不适用于MVC 5 另外,MVC 5为用户分配资源的最佳实践是什么?(例如,

  • 我有Kafka Streams java应用程序启动并运行。我试图使用KSQL创建简单的查询,并使用Kafka流来实现复杂的解决方案。我希望将KSQL和Kafka流作为Java应用程序运行。 我打算通过https://github.com/confluentinc/ksql/blob/master/ksqldb-examples/src/main/java/io/confluent/ksql/em

  • 本文向大家介绍Springboot+SpringSecurity+JWT实现用户登录和权限认证示例,包括了Springboot+SpringSecurity+JWT实现用户登录和权限认证示例的使用技巧和注意事项,需要的朋友参考一下 如今,互联网项目对于安全的要求越来越严格,这就是对后端开发提出了更多的要求,目前比较成熟的几种大家比较熟悉的模式,像RBAC 基于角色权限的验证,shiro框架专门用于

  • 我有一个Web应用程序,它对不同端口上的Web服务执行ajax请求(即我的应用程序和服务器位于不同的域中)。 我无法访问服务器 API,因此我无法使用 JSONP。 我正在使用Smiley的HTTP代理Servlet进行解析,因此我的web.xml文件包含以下部分: 不幸的是,我必须在不同的机器(开发、测试、生产)上部署web应用程序,这些机器响应不同的IP地址<是否有一种方法可以在web上动态更

  • 我希望使用Spring Security性和Json Web令牌(JWT)保护我的服务,并使用spring会话将登录用户存储在redis中。所以,当用户发送登录请求时,我对用户进行身份验证,并将生成的令牌发送回,如下所示: 我还将该用户添加到会话(支持Redis会话): 在我检查redis之后,我看到用户会话已经设置为redis。但当我收到来自用户的下一次尝试时,它变成了匿名用户,理想情况下它不应