|
7 | 7 | languages: |
8 | 8 | - JavaScript |
9 | 9 | - TypeScript |
| 10 | + - Rust |
10 | 11 | preview: |
11 | 12 | - true |
12 | 13 | pcx_content_type: example |
@@ -258,4 +259,75 @@ export default { |
258 | 259 | } satisfies ExportedHandler<Env>; |
259 | 260 | ``` |
260 | 261 |
|
261 | | -</TabItem> </Tabs> |
| 262 | +</TabItem> <TabItem label="Rust" icon="seti:rust"> |
| 263 | +```rs |
| 264 | +use base64::prelude::*; |
| 265 | +use worker::*; |
| 266 | + |
| 267 | +#[event(fetch)] |
| 268 | +async fn fetch(req: Request, env: Env, _ctx: Context) -> Result<Response> { |
| 269 | + let basic_user = "admin"; |
| 270 | + // You will need an admin password. This should be |
| 271 | + // attached to your Worker as an encrypted secret. |
| 272 | + // Refer to https://developers.cloudflare.com/workers/configuration/secrets/ |
| 273 | + let basic_pass = match env.secret("PASSWORD") { |
| 274 | + Ok(s) => s.to_string(), |
| 275 | + Err(_) => "password".to_string(), |
| 276 | + }; |
| 277 | + let url = req.url()?; |
| 278 | + |
| 279 | + match url.path() { |
| 280 | + "/" => Response::ok("Anyone can access the homepage."), |
| 281 | + // Invalidate the "Authorization" header by returning a HTTP 401. |
| 282 | + // We do not send a "WWW-Authenticate" header, as this would trigger |
| 283 | + // a popup in the browser, immediately asking for credentials again. |
| 284 | + "/logout" => Response::error("Logged out.", 401), |
| 285 | + "/admin" => { |
| 286 | + // The "Authorization" header is sent when authenticated. |
| 287 | + let authorization = req.headers().get("Authorization")?; |
| 288 | + if authorization == None { |
| 289 | + let mut headers = Headers::new(); |
| 290 | + // Prompts the user for credentials. |
| 291 | + headers.set( |
| 292 | + "WWW-Authenticate", |
| 293 | + "Basic realm='my scope', charset='UTF-8'", |
| 294 | + )?; |
| 295 | + return Ok(Response::error("You need to login.", 401)?.with_headers(headers)); |
| 296 | + } |
| 297 | + let authorization = authorization.unwrap(); |
| 298 | + let auth: Vec<&str> = authorization.split(" ").collect(); |
| 299 | + let scheme = auth[0]; |
| 300 | + let encoded = auth[1]; |
| 301 | + |
| 302 | + // The Authorization header must start with Basic, followed by a space. |
| 303 | + if encoded == "" || scheme != "Basic" { |
| 304 | + return Response::error("Malformed authorization header.", 400); |
| 305 | + } |
| 306 | + |
| 307 | + let buff = BASE64_STANDARD.decode(encoded).unwrap(); |
| 308 | + let credentials = String::from_utf8_lossy(&buff); |
| 309 | + // The username & password are split by the first colon. |
| 310 | + //=> example: "username:password" |
| 311 | + let credentials: Vec<&str> = credentials.split(':').collect(); |
| 312 | + let user = credentials[0]; |
| 313 | + let pass = credentials[1]; |
| 314 | + |
| 315 | + if user != basic_user || pass != basic_pass { |
| 316 | + let mut headers = Headers::new(); |
| 317 | + // Prompts the user for credentials. |
| 318 | + headers.set( |
| 319 | + "WWW-Authenticate", |
| 320 | + "Basic realm='my scope', charset='UTF-8'", |
| 321 | + )?; |
| 322 | + return Ok(Response::error("You need to login.", 401)?.with_headers(headers)); |
| 323 | + } |
| 324 | + |
| 325 | + let mut headers = Headers::new(); |
| 326 | + headers.set("Cache-Control", "no-store")?; |
| 327 | + Ok(Response::ok("🎉 You have private access!")?.with_headers(headers)) |
| 328 | + } |
| 329 | + _ => Response::error("Not Found.", 404), |
| 330 | + } |
| 331 | +} |
| 332 | +``` |
| 333 | +</TabItem> </Tabs> |
0 commit comments