Rust 使用 Actix-Web 验证 Auth Web 微服务-整教程第 3 部分 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
krircc
V2EX    Rust

Rust 使用 Actix-Web 验证 Auth Web 微服务-整教程第 3 部分

  •  
  •   krircc 2018-11-27 10:28:25 +08:00 3519 次点击
    这是一个创建于 2563 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Rust 使用 Actix-Web 验证 Auth Web 微服务-整教程第 3 部分

    本文同步与Rust 中文社区 时间:2018-11-27,作者:krircc, 简介:天青色

    欢迎向 Rust 中文社区投稿,投稿地址,好文将在以下地方直接展示

    1. Rust 中文社区首页
    2. Rust 中文社区Rust 文章栏目
    3. 知乎专栏Rust 语言

    更新我们的 CARGO.TOML

    Rust 生态系统正在快速发展,在几个星期内,我们的许多箱子都在上游更新,包括我的 sparkpost 箱子(稍后会详细介绍)。没有任何延迟,我们只需更新 cargo.toml 文件中的以下条件箱。

    [dependencies] actix = "0.7.7" actix-web = "0.7.14" env_logger = "0.6.0" r2d2 = "0.8.3" sparkpost = "0.5.2" 

    使用 SPARKPOST 发送注册电子邮件

    请随意使用您喜欢的任何电子邮件服务(除个人使用外,我与sparkpost没有关联),只要您能够复制已发送的电子邮件即可。现在,您需要在.env文件中添加以下内容。

    SPARKPOST_API_KEY='yourapikey' SENDING_EMAIL_ADDRESS='[email protected]' 

    Api 密钥是从 sparkpost 帐户获得的,只要您拥有可以控制的域名,就可以免费创建一个。要处理电子邮件,我们创建一个文件email_service.rs并添加以下内容。

    use models::Invitation; use sparkpost::transmission::{ EmailAddress, Message, Options, Recipient, Transmission, TransmissionResponse, }; fn get_api_key() -> String { std::env::var("SPARKPOST_API_KEY").expect("SPARKPOST_API_KEY must be set") } #[allow(unused)] pub fn send_invitation(invitation: &Invitation) { let tm = Transmission::new_eu(get_api_key()); let sending_email = std::env::var("SENDING_EMAIL_ADDRESS").expect("SENDING_EMAIL_ADDRESS must be set"); // new email message with sender name and email let mut email = Message::new(EmailAddress::new(sending_email, "Let's Organise")); // set options for a transactional email for now let optiOns= Options { open_tracking: false, click_tracking: false, transactional: true, sandbox: false, inline_css: false, start_time: None, }; // recipient from the invitation email let recipient: Recipient = invitation.email.as_str().into(); let email_body = format!( "Please click on the link below to complete registration. <br/> <a href=\"http://localhost:3000/register.html?id={}&email={}\"> http://localhost:3030/register</a> <br> your Invitation expires on <strong>{}</strong>", invitation.id, invitation.email, invitation .expires_at .format("%I:%M %p %A, %-d %B, %C%y") .to_string() ); // complete the email message with details email .add_recipient(recipient) .options(options) .subject("You have been invited to join Simple-Auth-Server Rust") .html(email_body); let result = tm.send(&email); match result { Ok(res) => { // println!("{:?}", &res); match res { TransmissionResponse::ApiResponse(api_res) => { println!("API Response: \n {:#?}", api_res); // assert_eq!(1, api_res.total_accepted_recipients); // assert_eq!(0, api_res.total_rejected_recipients); } TransmissionResponse::ApiError(errors) => { println!("Response Errors: \n {:#?}", &errors); } } } Err(error) => { println!("error \n {:#?}", error); } } } 

    为了能够在我们的应用程序中使用此服务,我们在main.js文件中添加extern crate sparkpost;mod email_service;。请注意,我们不会从send_invitation函数返回任何内容。这取决于您在真实应用中想要做什么,现在我们只需登录终端。

    调整您的邀请处理

    在上一个教程中,我们以一种返回对象本身的方式实现了我们的邀请。让我们改变它并将电子邮件发送给用户。在我们invitation_routes.rs中我们邀请通过调用send_invitation函数。代码如下所示。

    use actix_web::{AsyncResponder, FutureResponse, HttpResponse, Json, ResponseError, State}; use futures::future::Future; use app::AppState; use email_service::send_invitation; use invitation_handler::CreateInvitation; pub fn register_email( (signup_invitation, state): (Json<CreateInvitation>, State<AppState>), ) -> FutureResponse<HttpResponse> { state .db .send(signup_invitation.into_inner()) .from_err() .and_then(|db_response| match db_response { Ok(invitation) => { send_invitation(&invitation); Ok(HttpResponse::Ok().into()) } Err(err) => Ok(err.error_response()), }).responder() } 

    设置模拟前端进行测试

    我不打算详细介绍前端设置。在本教程中,我创建用以作为静态文件的一些HTML / CSS / JS文件的目的为了方便。你可以简单地将这个文件夹复制到你的代码的根目录作为'static /',或者狂野地做一个react / vue / angular前端。

    我们将稍微改变我们的路由以满足我们的需求,并将静态文件路由从业务逻辑路由中分离出来。我决定使用在根级别提供的静态文件,并将所有应用程序路径移动到/api前缀。为此,我们将app.rs文件修改为以下内容。

    use actix::prelude::*; use actix_web::middleware::identity::{CookieIdentityPolicy, IdentityService}; use actix_web::{fs, http::Method, middleware::Logger, App}; use auth_routes::{get_me, login, logout}; use chrono::Duration; use invitation_routes::register_email; use models::DbExecutor; use register_routes::register_user; pub struct AppState { pub db: Addr<DbExecutor>, } /// creates and returns the app after mounting all routes/resources pub fn create_app(db: Addr<DbExecutor>) -> App<AppState> { // secret is a random minimum 32 bytes long base 64 string let secret: String = std::env::var("SECRET_KEY").unwrap_or_else(|_| "0123".repeat(8)); let domain: String = std::env::var("DOMAIN").unwrap_or_else(|_| "localhost".to_string()); App::with_state(AppState { db }) .middleware(Logger::default()) .middleware(IdentityService::new( CookieIdentityPolicy::new(secret.as_bytes()) .name("auth") .path("/") .domain(domain.as_str()) .max_age(Duration::days(1)) .secure(false), // this can only be true if you have https )) // everything under '/api/' route .scope("/api", |api| { // routes for authentication api.resource("/auth", |r| { r.method(Method::POST).with(login); r.method(Method::DELETE).with(logout); r.method(Method::GET).with(get_me); }) // routes to invitation .resource("/invitation", |r| { r.method(Method::POST).with(register_email); }) // routes to register as a user after the .resource("/register/{invitation_id}", |r| { r.method(Method::POST).with(register_user); }) }) // serve static files .handler( "/", fs::StaticFiles::new("./static/") .unwrap() .index_file("index.html"), ) } 

    请注意封闭所有路由的scope方法。这就是设置电子邮件验证和简单前端所需的全部内容。

    英文原文

    /div>
    1 条回复    2018-11-27 14:00:50 +08:00
    del1214
        1
    del1214  
       2018-11-27 14:00:50 +08:00
    真棒, 不过不会
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2860 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 00:28 PVG 08:28 LAX 16:28 JFK 19:28
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86