Browse Source

Add a full example for custom provider configuration.

master
Chris Zehner Jeb Rosen <jeb@jebrosen.com> 1 month ago
parent
commit
b27a55f9a8
8 changed files with 150 additions and 1 deletions
  1. +1
    -1
      Cargo.toml
  2. +4
    -0
      examples/user_info_custom_provider/.gitignore
  3. +14
    -0
      examples/user_info_custom_provider/Cargo.toml
  4. +5
    -0
      examples/user_info_custom_provider/Rocket.toml.example
  5. +1
    -0
      examples/user_info_custom_provider/rust-toolchain
  6. +50
    -0
      examples/user_info_custom_provider/src/main.rs
  7. +74
    -0
      examples/user_info_custom_provider/src/oauth2/github.rs
  8. +1
    -0
      examples/user_info_custom_provider/src/oauth2/mod.rs

+ 1
- 1
Cargo.toml View File

@@ -11,7 +11,7 @@ readme = "README.md"
edition = "2018"

[workspace]
members = ["examples/user_info_hyper_sync_rustls"]
members = ["examples/user_info_hyper_sync_rustls", "examples/user_info_custom_provider"]

[features]
default = ["hyper_sync_rustls_adapter"]


+ 4
- 0
examples/user_info_custom_provider/.gitignore View File

@@ -0,0 +1,4 @@
Cargo.lock
Rocket.toml
/target
**/*.rs.bk

+ 14
- 0
examples/user_info_custom_provider/Cargo.toml View File

@@ -0,0 +1,14 @@
[package]
name = "user_info_custom_provider"
version = "0.0.0"
authors = ["Chris Zehner <cbzehner@gmail.com>"]
publish = false
edition = "2018"

[dependencies]
hyper = "0.10"
hyper-sync-rustls = "=0.3.0-rc.4"
rocket = "0.4.2"
rocket_oauth2 = { path = "../../", features = ["hyper_sync_rustls_adapter"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

+ 5
- 0
examples/user_info_custom_provider/Rocket.toml.example View File

@@ -0,0 +1,5 @@
[global.oauth.github]
provider = { auth_uri = "https://github.com/login/oauth/authorize", token_uri = "https://github.com/login/oauth/access_token" }
client_id = "<client_id>"
client_secret = "<client_secret>"
redirect_uri = "http://localhost:8000/auth/github"

+ 1
- 0
examples/user_info_custom_provider/rust-toolchain View File

@@ -0,0 +1 @@
nightly

+ 50
- 0
examples/user_info_custom_provider/src/main.rs View File

@@ -0,0 +1,50 @@
#![feature(decl_macro, proc_macro_hygiene)]

use rocket::http::{Cookie, Cookies};
use rocket::request::{self, FromRequest, Request};
use rocket::response::Redirect;
use rocket::{get, routes, Outcome};

mod oauth2;

struct User {
pub username: String,
}

impl<'a, 'r> FromRequest<'a, 'r> for User {
type Error = ();

fn from_request(request: &'a Request<'r>) -> request::Outcome<User, ()> {
let mut cookies = request.guard::<Cookies<'_>>().expect("request cookies");
if let Some(cookie) = cookies.get_private("username") {
return Outcome::Success(User {
username: cookie.value().to_string(),
});
}

Outcome::Forward(())
}
}

#[get("/")]
fn index(user: User) -> String {
format!("Hi, {}!", user.username)
}

#[get("/", rank = 2)]
fn index_anonymous() -> &'static str {
"Please login (/login/github)"
}

#[get("/logout")]
fn logout(mut cookies: Cookies<'_>) -> Redirect {
cookies.remove(Cookie::named("username"));
Redirect::to("/")
}

fn main() {
rocket::ignite()
.mount("/", routes![index, index_anonymous, logout])
.attach(oauth2::github::fairing())
.launch();
}

+ 74
- 0
examples/user_info_custom_provider/src/oauth2/github.rs View File

@@ -0,0 +1,74 @@
use std::io::Read;

use hyper::{
header::{qitem, Accept, Authorization, UserAgent},
mime::Mime,
net::HttpsConnector,
Client,
};
use hyper_sync_rustls;
use rocket::fairing::Fairing;
use rocket::http::{Cookie, Cookies, SameSite};
use rocket::request::Request;
use rocket::response::Redirect;
use rocket_oauth2::hyper_sync_rustls_adapter::HyperSyncRustlsAdapter;
use rocket_oauth2::{OAuth2, TokenResponse};
use serde_json;

/// User information to be retrieved from the GitHub API.
#[derive(serde::Deserialize)]
struct GitHubUserInfo {
#[serde(default)]
name: String,
}

/// Rocket fairing for managing the GitHub OAuth2 flow
///
/// The third argument passed into OAuth2::fairing is the
/// config_name which must match the key used in Rocket.toml
/// to specify the custom provider attributes.
pub fn fairing() -> impl Fairing {
OAuth2::fairing(
HyperSyncRustlsAdapter,
post_install_callback,
"github",
"/auth/github",
Some(("/login/github", vec![String::from("user:read")])),
)
}

/// Callback to handle the authenticated token recieved from GitHub
/// and store it as a private cookie
fn post_install_callback(
request: &Request<'_>,
token: TokenResponse,
) -> Result<Redirect, Box<dyn (::std::error::Error)>> {
let https = HttpsConnector::new(hyper_sync_rustls::TlsClient::new());
let client = Client::with_connector(https);

// Use the token to retrieve the user's GitHub account information.
let mime: Mime = "application/vnd.github.v3+json"
.parse()
.expect("parse GitHub MIME type");
let response = client
.get("https://api.github.com/user")
.header(Authorization(format!("token {}", token.access_token())))
.header(Accept(vec![qitem(mime)]))
.header(UserAgent("rocket_oauth2 demo application".into()))
.send()?;

if !response.status.is_success() {
return Err(format!("got non-success status {}", response.status).into());
}

let user_info: GitHubUserInfo = serde_json::from_reader(response.take(2 * 1024 * 1024))?;

// Set a private cookie with the user's name, and redirect to the home page.
let mut cookies = request.guard::<Cookies<'_>>().expect("request cookies");
cookies.add_private(
Cookie::build("username", user_info.name)
.same_site(SameSite::Lax)
.finish(),
);
Ok(Redirect::to("/"))
}

+ 1
- 0
examples/user_info_custom_provider/src/oauth2/mod.rs View File

@@ -0,0 +1 @@
pub mod github;

Loading…
Cancel
Save