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

栏目: 编程语言 · Rust · 发布时间: 5年前

内容简介:本文同步与时间:2018-11-27,作者:欢迎向Rust中文社区投稿,

本文同步与 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='register@yourdomain.com'

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 方法。这就是设置电子邮件验证和简单前端所需的全部内容。

英文原文


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

新内容创业:我这样打造爆款IP

新内容创业:我这样打造爆款IP

南立新、曲琳 / 机械工业出版社 / 2016-5-10 / 39.00

这是个内容创业爆棚的时代,在采访几十家内容创业公司,与一线最优秀的创业者独家对话之后,作者写作了这本书,其中包括对这个行业的真诚感触,以及希望沉淀下来的体系化思考。 本书共分三个部分讲述了爆红大号的内容创业模式和方法。其中第一部分,讲述了新的生产方式,即内容形态发展的现状--正在被塑造;第二部分,讲述了新的盈利探索,即从贩卖产品到贩卖内容的转变,该部分以多个案例进行佐证,内容翔实;第三部分,......一起来看看 《新内容创业:我这样打造爆款IP》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具