1. 程式人生 > >Rust使用Actix-Web驗證Auth Web微服務-整教程第3部分

Rust使用Actix-Web驗證Auth Web微服務-整教程第3部分

本文同步與Rust中文社群
時間:2018-11-27,作者:krircc, 簡介:天青色

歡迎向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方法。這就是設定電子郵件驗證和簡單前端所需的全部內容。

英文原文

相關推薦

Rust使用Actix-Web驗證Auth Web服務-教程3部分

本文同步與Rust中文社群時間:2018-11-27,作者:krircc, 簡介:天青色 歡迎向Rust中文社群投稿,投稿地址,好文將在以下地方直接展示 更新我們的CARGO.TOML Rust生態系統正在快速發展,在幾個星期內,我們的許多箱子都在上游更新,包括我

服務系列教程

課程 分析 paas pos 更多 註意 解析 二維碼 idea 視頻課程包含:微服務精品課程包含Spring Cloud基礎視頻教程、Spring Cloud高級教程+項目實戰、Spring boot入門教程、Spring boot進階教程、Spring Ecosyste

最新Java服務架構教程

2018年Java微服務架構視訊教程 ├─第1章 微服務簡介   4課 │      Java教程:001構建單體應用.mp4 │      Java教程:002微服務解決複雜問題.mp4 │&nbs

最新從天氣專案看Spring Cloud服務治理教程

第1章 導學及SpringCloud基石SpringBoot Spring Boot簡單介紹及入門 第2章 基於Spring Boot快速構建天氣預報系統 基於Spring Boot技術快速迭代,實現天氣預報系統 第3章 服務拆分與業務建模 全面講解了微服務架構原理、產生背景,以及如何來設計微

服務入門教程之<環境搭建>:Springboot+mybatis+themleaf+zookeeper+dubbo

首先說明下我這裡用的環境是:Springboot+mybatis+themleaf;Linxu下安裝Ubuntu,JDK1.8,zookeeper,dubbo 沒有用Docker,其實可以用Docker拉取這些映象,只不過我嫌麻煩,就先用這個了,其實只要掌握了Docker如何拉取映象,設定固定IP之後,用法

服務架構設計 五步: 服務的 User Stories 的拆分與澄清

2016.9.11, 深圳, Ken Fang 特性負責人與架構師, 開發骨幹人員, 測試經理, 資深測試人員, 經由協作, 完成了: 1.  微服務邊界上下文 (Bounded Context) 的界定。 2.  微服務架構設計; 架構方案的選定。 3.  微服務架構上

2019最全小馬哥Spring Cloud系列Java服務實踐教程

ava 微服務實踐 - Spring Cloud 系列(一)雲原生應用.wmvJava 微服務實踐 - Spring Cloud 系列(二)配置客戶端.wmvJava 微服務實踐 - Spring Cloud 系列(三)配置伺服器.mp4Java 微服務實踐 - Spring Cloud 系列(四)

Jhipster 建立服務詳細教程

一、簡介 jHipster 集成了springcloud的註冊中心(eureka server)和配置中心(config server),eureka server 能夠將我們自己開發的微服務(Microservices)都納入到它自身當中,config server 能夠

服務架構設計 六步: 服務的 User Stories 的分析、設計與定義完成

2016.9.12, 深圳, Ken Fang 特性負責人, 說服開發與測試人員, 能認同微服務中的 User Story 的價值, 並使開發與測試人員能從產品外部的視角, 清楚的明白: 外部使用者、系統、裝置或事件所期望的微服務中的 User Story 完成的定義或標準

《深入理解Spring Cloud與服務構建》2章 Spring Cloud簡介

開發十年,就只剩下這套架構體系了! >>>   

spring cloud服務快速教程之(四)熔斷器(Hystrix)及其工具(Dashboard、Turbine)

0-為什麼需要熔斷器   在分散式系統中,各個服務相互呼叫相互依賴,如果某個服務掛了,很可能導致其他呼叫它的一連串服務也掛掉或者在不斷等待中耗盡伺服器資源,這種現象稱之為雪崩效應;   未來防止系統雪崩,熔斷機制必不可少,就是當一個服務掛掉後,呼叫它的服務能快速熔斷,不再耗費資源,快速失敗並提供回退方案;

spring cloud服務快速教程之(七) Spring Cloud Alibaba--nacos(一)、服務註冊發現

0、前言   什麼是Spring Cloud Alibaba?   Spring Cloud Alibaba 是阿里開源的,致力於提供微服務開發的一站式解決方案。此專案包含開發分散式應用微服務的必需元件,方便開發者通過 Spring Cloud 程式設計模型輕鬆使用這些元件來開發分散式應用服務。  

spring cloud服務快速教程之(十一) Sleuth(zipkin) 服務鏈路追蹤

0、前言    微服務架構上眾多微服務通過REST呼叫,可能需要很多個服務協同才能完成一個介面功能,如果鏈路上任何一個服務出現問題或者網路超時,都會形成導致介面呼叫失敗。隨著業務的不斷擴張,服務之間互相呼叫會越來越複雜。如何清晰地記錄服務的呼叫鏈路,方便將來問題的定位,Spring cloud sleuth元

spring cloud服務快速教程之(十二) 分散式ID解決方案(mybatis-plus篇)

0-前言   分散式系統中,分散式ID是個必須解決的問題點;   雪花演算法是個好方式,不過不能直接使用,因為如果直接使用的話,需要配置每個例項workerId和datacenterId,在微服務中,例項一般動態配置,直接指定具體例項的這兩個引數是不現實的;   所以,一般採用雪花演算法的變種,主要是將這兩個

docker集群部署:3部分服務

註意 sources 計算 error compose image 共享端口 port url docker集群部署:第3部分:服務 介紹在第3部分中,我們將擴展應用程序並實現負載平衡。 關於服務在分布式應用程序中,應用程序的不同部分被稱為“服務”。例如,一個視頻共享站點

Rational Functional Tester Proxy SDK 開發, 3 部分: 使用 Proxy SDK 擴充套件 Java GUI 元件可捕獲的驗證資料

本系列的上一篇介紹瞭如何通過 Proxy 擴充套件測試元件的識別屬性和方法。除了識別物件,RFT 也提供了較完善的驗證功能,分為屬性驗證(properties verification)和資料驗證(data verification point)兩種。本篇主要介紹如何通

Karaf教程2部分 使用Configuration Admin服務

    在Karaf教程的第1部分,我們學習瞭如何使用maven和blueprint提供和使用pojo服務,如何使用http服務釋出servlet。     在第2部分,我們集中精力關注OSGi bundle的配置。不像servlet容器,OSGi容器包含一個非常好的配置

服務架構中的身份驗證問題 :JSON Web Tokens( JWT)

場景介紹 軟體安全是一件很負責的問題,由於微服務系統中每個服務都要處理安全問題,所以在微服務場景下會更加複雜,一般我們會四種面向微服務系統的身份驗證方案。 在傳統的單體架構中,單個服務儲存所有的使用者資料,可以校驗使用者,並在認證成功後建立HTTP會

基於容器與服務架構的Web應用實踐eShopOnContainers

contain 安全 github ima 微服務架構 使用 服務架構 ctu target 微軟官方提供了一個基於Docker和微服務的示例應用eShopOnContainers;它使用了面向服務的架構並且從服務端到客戶端都是跨平臺的;該架構使用通過http作為客戶端與服

最近整理出了有關大資料,微服務,分散式,Java,Python,Web前端,產品運營,互動等1.7G的學習資料,有視訊教程,原始碼,課件,工具,面試題等等。這裡將珍藏多年的資源免費分享給各位小夥伴們

大資料,微服務,分散式,Java,Python,Web前端,產品運營,互動 領取方式在篇尾!!! 基礎篇、網際網路架構,高階程式設計師必備視訊,架構師系列視訊,各框架原始碼解析視訊,Linux系統、JVM、大型分散式電商專案實戰視訊........等等