rust中使用actix-session时设置Cookie失败问题

问题:浏览器端cookie没有设置成功, 后来注意到header的Set-Cookie:参数后面有带着secure的属性。

提示:

尝试通过Set-Cookie标头设置Cookie时被阻止,因为它具有"Secure"属性,但未通过安全连接发送

This attempt to set a cookie via a Set-Cookie header was blocked because it had the Secure attribute but was not recerved over a secure connection

原因:

设置了secure属性的cookie只能用https协议发送给服务器

解决

去掉secure属性,可以使用http协议发送给服务器

setcookie(
    string $name,
    string $value = "",
    int $expires = 0,
    string $path = "",
    string $domain = "",
    bool $secure = false,
    bool $httponly = false
): bool

secure属性设置这个 Cookie 是否仅仅通过安全的 HTTPS 连接传给客户端。 设置成 true 时,只有安全连接存在时才会设置 Cookie。 如果是在服务器端处理这个需求,程序员需要仅仅在安全连接上发送此类 Cookie。

通常无法设置cookie还有其他原因比如跨域问题,显然这里不是,只是在测试环境里使用默认https链接,对于一般开发环境使用http,这里没有使用跨域请求,如果使用了,需要在后端设置,还需要在前端设置允许请求携带cookie,特别是ajax请求。举例java中设置跨域

public class CorsInterceptor extends HandlerInterceptorAdapter {

    @Value("${service.corsOrigin}")  //跨域自定义配置application.yml自己配置
    private String corsOrigin;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String origin = request.getHeader("Origin");
        //后端响应基本配置项
        if (!StringUtils.isEmpty(origin) && corsOrigin.contains(origin)) {
            response.setHeader("Access-Control-Allow-Origin", origin);
            response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
            response.setHeader("Access-Control-Allow-Methods", "POST, GET");
            response.setHeader("Access-Control-Allow-Credentials", "true");
        }
        //设备默认值
        response.setContentType("application/json;charset=UTF-8");
        return true;
    }
}

setHeader设置的必要性

"Access-Control-Allow-Origin"需要指定前端指定域名,不能用*号,否则无法实现跨域

"Access-Control-Allow-Credentials" 设置成true是告知前端可以请求头携带cookie请求,否则前端将无法进行请求,另外前端每次都会发两次请求,其中首次是options请求,该请求为试探性请求可以被拦截器捕获,然后给与前端上述响应的内容,告知对它开放的一些权限及要求。

2.拦截器最后要实现WebMvcConfigurer开启拦截器配置,否则上面的代码无法生效,springMVC机制

@Configuration
public class BaseInterceptor implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(getCorsInterceptor());
    }

    @Bean
    public CorsInterceptor getCorsInterceptor() {
        return new CorsInterceptor();
    }
}

这里使用的是actix-session框架,session存在redis中默认需要安装链接才能存储cookie,否则会被禁止。

解决:要解决无法设置cookie问题回归cookie的属性上,目前已经携带secure属性,要求是https的方式才能接收,现在要做的是将该属性去除或者设置false。

解决方式:在中间件层额外设置cookie的属性设置,如果使用redis存储添加依赖

//redis 
cargo add actix-session --features=redis-session
//本地服务器
cargo add actix-session --features=cookie-session
//redis服务器安装认证
cargo add actix-session --features=redis-session-native-tls
//其他
cargo add actix-session --features=redis-session-rustls

这里拿redis举例,

//构建中间键插件
fn session_middleware(redis: RedisSessionStore) -> SessionMiddleware<RedisSessionStore> {
    //  RedisActorSessionStore::new("127.0.0.1:6379");
    SessionMiddleware::builder(redis, Key::from(&[0; 64]))
        .cookie_name(String::from("my-kata-cookie")) // arbitrary name
        .cookie_secure(false) // https only
        .session_lifecycle(BrowserSession::default()) // expire at end of session
        .cookie_same_site(SameSite::Lax)
        .cookie_content_security(CookieContentSecurity::Private) // encrypt
        .cookie_http_only(true) // disallow scripts from reading
        .build()
}

//在应用上加入该方法添加中间件
 .wrap(session_middleware(redis_store.clone()))

如上所示修改cookie的属性通过构建的方式来完成,很多会学习其他编程语言习惯从httpResonse中处理,在rust中没有提供基础功能,甚至那些最基础的功能也要靠导入包完成,这主要是rust还不够成熟,包的变更兼容差异很大,如上所示Cookie的secure属性设置为false,前端收到就不会报安全连接使用https才能保存cookie的弊端,当然如果你加一成nginx,可以过度性地将该属性直接去掉。

创建方式不同,如果您想自定义cookie的更多信息,请使用 builder 而不是 new

  //使用默认
 .wrap(SessionMiddleware::new(redis_store.clone(), key.clone()))
   
//使用自定义
   .wrap(
                    SessionMiddleware::builder(storage.clone(), secret_key.clone())
                        .session_lifecycle(
                            PersistentSession::default().session_ttl(time::Duration::days(5)),
                        )
                        .build(),
                )

对于引用本地保存的就更简单,不需要设置连接redis处理,如下

//本地服务器
cargo add actix-session --features=cookie-session

fn local_session_middleware() -> SessionMiddleware<CookieSessionStore> {
    SessionMiddleware::builder(CookieSessionStore::default(), Key::from(&[0; 64]))
        .cookie_name(String::from("my-kata-cookie")) // arbitrary name
        .cookie_secure(false) // https only
        .session_lifecycle(BrowserSession::default()) // expire at end of session
        .cookie_same_site(SameSite::Strict)
        .cookie_content_security(CookieContentSecurity::Private) // encrypt
        .cookie_http_only(true) // disallow scripts from reading
        .build()
}

使用redis存储时,注意先构建存储实例,不同的存储方式实例创建不同,这里是在外面创建传入函数,还可以直接使用构建类型,直接创建如下:

 .wrap(
                SessionMiddleware::builder(
                    RedisActorSessionStore::new("127.0.0.1:6379"),
                    secret_key.clone(),
                )
                .build(),
            )

总结不易,希望点赞多多关注。

相关推荐
diemeng11191 小时前
AI前端开发技能变革时代:效率与创新的新范式
前端·人工智能
bin91533 小时前
DeepSeek 助力 Vue 开发:打造丝滑的复制到剪贴板(Copy to Clipboard)
前端·javascript·vue.js·ecmascript·deepseek
勤奋的凯尔森同学3 小时前
webmin配置终端显示样式,模仿UbuntuDesktop终端
linux·运维·服务器·ubuntu·webmin
丁卯4044 小时前
Go语言中使用viper绑定结构体和yaml文件信息时,标签的使用
服务器·后端·golang
chengooooooo4 小时前
苍穹外卖day8 地址上传 用户下单 订单支付
java·服务器·数据库
晴空万里藏片云4 小时前
elment Table多级表头固定列后,合计行错位显示问题解决
前端·javascript·vue.js
曦月合一4 小时前
html中iframe标签 隐藏滚动条
前端·html·iframe
奶球不是球4 小时前
el-button按钮的loading状态设置
前端·javascript
kidding7234 小时前
前端VUE3的面试题
前端·typescript·compositionapi·fragment·teleport·suspense
人间打气筒(Ada)5 小时前
MySQL主从架构
服务器·数据库·mysql