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

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

内容简介:本文同步与时间: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 方法。这就是设置电子邮件验证和简单前端所需的全部内容。

英文原文


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

查看所有标签

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

Algorithms

Algorithms

Sanjoy Dasgupta、Christos H. Papadimitriou、Umesh Vazirani / McGraw-Hill Education / 2006-10-16 / GBP 30.99

This text, extensively class-tested over a decade at UC Berkeley and UC San Diego, explains the fundamentals of algorithms in a story line that makes the material enjoyable and easy to digest. Emphasi......一起来看看 《Algorithms》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具