[英]How to implement Microsoft Azure Blob storage for browser with environment variables?
[英]Is it insecure and bad practice to expose your environment variables to the browser in NextJS?
我目前正在尝试在我正在使用的 NextJS 应用程序中设置 Firebase v9 身份验证。 我最初尝试将 Next 的服务器端环境变量用于我的 Firebase 配置,但注意到我的所有环境变量一直未定义。 但后来我更新了我的 Firebase 配置以使用NEXT_PUBLIC_
然后它工作正常。 所以我想我的问题是:
下面我按顺序提供了我的 firebase 配置文件、AuthContext 提供程序和登录页面。
import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';
const firebaseConfig = {
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
databaseURL: process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL,
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET_URL,
messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID,
};
const app = initializeApp(firebaseConfig);
export const auth = getAuth();
import { createContext, useContext, useEffect, useState } from 'react';
import {
onAuthStateChanged,
signInWithEmailAndPassword,
signOut,
} from 'firebase/auth';
import { auth } from '@/lib/firebaseApp';
const AuthContext = createContext({});
export const useAuth = () => useContext(AuthContext);
export function AuthContextProvider({ children }) {
const [user, setUser] = useState({ email: null, uid: null });
const [loading, setLoading] = useState(true);
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
if (user) {
setUser({
email: user.email,
uid: user.uid,
});
} else {
setUser({ email: null, uid: null });
}
});
setLoading(false);
return () => unsubscribe();
}, []);
function login(email, password) {
return signInWithEmailAndPassword(auth, email, password);
}
async function logout() {
setUser({ email: null, uid: null });
await signOut(auth);
}
return (
<AuthContext.Provider value={{ user, login, logout }}>
{loading ? null : children}
</AuthContext.Provider>
);
}
import { useState } from 'react';
import { useRouter } from 'next/router';
import { Button } from '@/components';
import { useAuth } from '@/context/AuthContext';
export default function Login() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const { login } = useAuth();
const router = useRouter();
async function handleSubmit(event) {
event.preventDefault();
try {
await login(email, password);
router.push('/dashboard');
} catch (error) {
console.log(error.message);
}
}
return (
<div className="flex min-h-full flex-col justify-center py-12 sm:px-6 lg:px-8">
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
<div className="mx-auto w-11/12 rounded-2xl border border-zinc-100 p-6 py-8 px-4 dark:border-zinc-700/40 sm:px-10 md:w-full">
<form className="space-y-6" onSubmit={(event) => handleSubmit(event)}>
<div>
<label
htmlFor="email"
className="block text-sm font-semibold text-zinc-900 dark:text-zinc-100"
>
Email address
</label>
<div className="mt-1">
<input
id="email"
name="email"
type="email"
autoComplete="email"
required
className="block w-full appearance-none rounded-md border border-zinc-900/10 bg-white px-3 py-2 shadow-sm shadow-zinc-800/5 placeholder:text-zinc-400 focus:border-teal-500 focus:outline-none focus:ring-4 focus:ring-teal-500/10 dark:border-zinc-700 dark:bg-zinc-700/[0.15] dark:text-zinc-200 dark:placeholder:text-zinc-500 dark:focus:border-teal-400 dark:focus:ring-teal-400/10 sm:text-sm"
onChange={(e) => setEmail(e.target.value)}
/>
</div>
</div>
<div>
<label
htmlFor="password"
className="block text-sm font-semibold text-zinc-900 dark:text-zinc-100"
>
Password
</label>
<div className="mt-1">
<input
id="password"
name="password"
type="password"
autoComplete="current-password"
required
className="block w-full appearance-none rounded-md border border-zinc-900/10 bg-white px-3 py-2 shadow-sm shadow-zinc-800/5 placeholder:text-zinc-400 focus:border-teal-500 focus:outline-none focus:ring-4 focus:ring-teal-500/10 dark:border-zinc-700 dark:bg-zinc-700/[0.15] dark:text-zinc-200 dark:placeholder:text-zinc-500 dark:focus:border-teal-400 dark:focus:ring-teal-400/10 sm:text-sm"
onChange={(e) => setPassword(e.target.value)}
/>
</div>
</div>
<div className="flex w-full justify-center">
<Button type="submit" className="w-10/12 px-6 py-4 md:w-5/6">
Sign In
</Button>
</div>
</form>
</div>
</div>
</div>
);
}
您当前正在客户端访问您的环境变量。 不需要此功能,因此默认情况下不存在,因为客户端上的所有内容对每个人都是可见的。 您可以直接以纯文本形式粘贴 API 密钥。 这是同一件事。
firebase 有两种选择。您可以使用 API 密钥公开的客户端 SDK,并且可以毫无问题地公开显示。 您在 firestore 控制台中编写自己的规则。 (这就是你似乎正在使用的)
重要如果您发布您的应用程序,您必须将 firestore 规则设置为锁定模式,并且只有在您专门为其编写规则时才允许读/写。
否则你可以使用 firebase admin SDK 应该只在服务器端运行。 然后你通过 Nextjs API 路由与 firebase 通信。 用于初始化此应用程序的 API 密钥是绝对私有的,不会被公开显示。 如果暴露,任何人都可以完全控制您的项目
您可以在此处阅读有关 firebase admin SDK 的更多信息: https://firebase.google.com/docs/admin/setup
您在客户端使用 firebase sdk,因此可以安全地公开您的 API 密钥。 但是不要忘记为谁可以读/写设置规则。 如果您的项目在发布时处于“测试模式”,任何人都可以控制您的应用
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.