emby支持无密码登录
This commit is contained in:
@@ -3514,6 +3514,7 @@ const EmbyConfigComponent = ({
|
||||
proxyPlay: false,
|
||||
customUserAgent: '',
|
||||
});
|
||||
const [authMode, setAuthMode] = useState<'apikey' | 'password'>('apikey');
|
||||
|
||||
// 从配置加载源列表
|
||||
useEffect(() => {
|
||||
@@ -3554,6 +3555,7 @@ const EmbyConfigComponent = ({
|
||||
proxyPlay: false,
|
||||
customUserAgent: '',
|
||||
});
|
||||
setAuthMode('apikey');
|
||||
setEditingSource(null);
|
||||
setShowAddForm(false);
|
||||
};
|
||||
@@ -3561,6 +3563,14 @@ const EmbyConfigComponent = ({
|
||||
// 开始编辑
|
||||
const handleEdit = (source: any) => {
|
||||
setFormData({ ...source });
|
||||
// 根据现有配置判断认证方式
|
||||
if (source.ApiKey) {
|
||||
setAuthMode('apikey');
|
||||
} else if (source.Username) {
|
||||
setAuthMode('password');
|
||||
} else {
|
||||
setAuthMode('apikey');
|
||||
}
|
||||
setEditingSource(source);
|
||||
setShowAddForm(false);
|
||||
};
|
||||
@@ -3579,6 +3589,19 @@ const EmbyConfigComponent = ({
|
||||
return;
|
||||
}
|
||||
|
||||
// 根据认证方式验证必填字段
|
||||
if (authMode === 'apikey') {
|
||||
if (!formData.ApiKey || !formData.UserId) {
|
||||
showError('使用密钥认证时,API Key 和用户 ID 为必填项', showAlert);
|
||||
return;
|
||||
}
|
||||
} else if (authMode === 'password') {
|
||||
if (!formData.Username) {
|
||||
showError('使用账号认证时,用户名为必填项', showAlert);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 验证key唯一性
|
||||
if (!editingSource && sources.some(s => s.key === formData.key)) {
|
||||
showError('标识符已存在,请使用其他标识符', showAlert);
|
||||
@@ -4088,67 +4111,119 @@ const EmbyConfigComponent = ({
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* API Key */}
|
||||
{/* 认证方式切换卡 */}
|
||||
<div>
|
||||
<label className='block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2'>
|
||||
API Key(推荐)
|
||||
认证方式 *
|
||||
</label>
|
||||
<input
|
||||
type='password'
|
||||
value={formData.ApiKey}
|
||||
onChange={(e) => setFormData({ ...formData, ApiKey: e.target.value })}
|
||||
placeholder='输入 Emby API Key'
|
||||
className='w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100'
|
||||
/>
|
||||
<p className='mt-1 text-xs text-gray-500 dark:text-gray-400'>
|
||||
推荐使用 API Key 认证。如果不使用 API Key,请填写下方的用户名和密码。
|
||||
</p>
|
||||
<div className='flex gap-2 mb-4'>
|
||||
<button
|
||||
type='button'
|
||||
onClick={() => {
|
||||
setAuthMode('apikey');
|
||||
// 切换到密钥认证时,清空用户名密码
|
||||
setFormData({ ...formData, Username: '', Password: '' });
|
||||
}}
|
||||
className={`flex-1 px-4 py-2 rounded-lg font-medium transition-colors ${
|
||||
authMode === 'apikey'
|
||||
? 'bg-blue-600 text-white'
|
||||
: 'bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-600'
|
||||
}`}
|
||||
>
|
||||
密钥认证
|
||||
</button>
|
||||
<button
|
||||
type='button'
|
||||
onClick={() => {
|
||||
setAuthMode('password');
|
||||
// 切换到账号认证时,清空 API Key 和 UserId
|
||||
setFormData({ ...formData, ApiKey: '', UserId: '' });
|
||||
}}
|
||||
className={`flex-1 px-4 py-2 rounded-lg font-medium transition-colors ${
|
||||
authMode === 'password'
|
||||
? 'bg-blue-600 text-white'
|
||||
: 'bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-600'
|
||||
}`}
|
||||
>
|
||||
账号认证
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 用户名 */}
|
||||
<div>
|
||||
<label className='block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2'>
|
||||
用户名(可选)
|
||||
</label>
|
||||
<input
|
||||
type='text'
|
||||
value={formData.Username}
|
||||
onChange={(e) => setFormData({ ...formData, Username: e.target.value })}
|
||||
placeholder='Emby 用户名'
|
||||
className='w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100'
|
||||
/>
|
||||
</div>
|
||||
{/* 密钥认证模式 */}
|
||||
{authMode === 'apikey' && (
|
||||
<>
|
||||
{/* API Key */}
|
||||
<div>
|
||||
<label className='block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2'>
|
||||
API Key *
|
||||
</label>
|
||||
<input
|
||||
type='password'
|
||||
value={formData.ApiKey}
|
||||
onChange={(e) => setFormData({ ...formData, ApiKey: e.target.value })}
|
||||
placeholder='输入 Emby API Key'
|
||||
className='w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100'
|
||||
/>
|
||||
<p className='mt-1 text-xs text-gray-500 dark:text-gray-400'>
|
||||
在 Emby 控制台的 API 密钥页面生成
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* 密码 */}
|
||||
<div>
|
||||
<label className='block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2'>
|
||||
密码(可选)
|
||||
</label>
|
||||
<input
|
||||
type='password'
|
||||
value={formData.Password}
|
||||
onChange={(e) => setFormData({ ...formData, Password: e.target.value })}
|
||||
placeholder='Emby 密码'
|
||||
className='w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100'
|
||||
/>
|
||||
</div>
|
||||
{/* 用户 ID */}
|
||||
<div>
|
||||
<label className='block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2'>
|
||||
用户 ID *
|
||||
</label>
|
||||
<input
|
||||
type='text'
|
||||
value={formData.UserId}
|
||||
onChange={(e) => setFormData({ ...formData, UserId: e.target.value })}
|
||||
placeholder='aab507c58e874de6a9bd12388d72f4d2'
|
||||
className='w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100'
|
||||
/>
|
||||
<p className='mt-1 text-xs text-gray-500 dark:text-gray-400'>
|
||||
从你的 Emby 抓包数据中获取用户 ID,通常在 URL 中如 /Users/[userId]/...
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* 用户 ID */}
|
||||
<div>
|
||||
<label className='block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2'>
|
||||
用户 ID(使用 API Key 时必填)
|
||||
</label>
|
||||
<input
|
||||
type='text'
|
||||
value={formData.UserId}
|
||||
onChange={(e) => setFormData({ ...formData, UserId: e.target.value })}
|
||||
placeholder='aab507c58e874de6a9bd12388d72f4d2'
|
||||
className='w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100'
|
||||
/>
|
||||
<p className='mt-1 text-xs text-gray-500 dark:text-gray-400'>
|
||||
从你的 Emby 抓包数据中获取用户 ID,通常在 URL 中如 /Users/[userId]/...
|
||||
</p>
|
||||
</div>
|
||||
{/* 账号认证模式 */}
|
||||
{authMode === 'password' && (
|
||||
<>
|
||||
{/* 用户名 */}
|
||||
<div>
|
||||
<label className='block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2'>
|
||||
用户名 *
|
||||
</label>
|
||||
<input
|
||||
type='text'
|
||||
value={formData.Username}
|
||||
onChange={(e) => setFormData({ ...formData, Username: e.target.value })}
|
||||
placeholder='Emby 用户名'
|
||||
className='w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100'
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 密码 */}
|
||||
<div>
|
||||
<label className='block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2'>
|
||||
密码(可选)
|
||||
</label>
|
||||
<input
|
||||
type='password'
|
||||
value={formData.Password}
|
||||
onChange={(e) => setFormData({ ...formData, Password: e.target.value })}
|
||||
placeholder='Emby 密码(如果账号没有密码可留空)'
|
||||
className='w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100'
|
||||
/>
|
||||
<p className='mt-1 text-xs text-gray-500 dark:text-gray-400'>
|
||||
如果 Emby 账号没有设置密码,可以留空
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* 启用开关 */}
|
||||
<div className='flex items-center justify-between'>
|
||||
|
||||
@@ -52,9 +52,9 @@ export async function POST(request: NextRequest) {
|
||||
return NextResponse.json({ error: '请填写 Emby 服务器地址' }, { status: 400 });
|
||||
}
|
||||
|
||||
if (!ApiKey && (!Username || !Password)) {
|
||||
if (!ApiKey && !Username) {
|
||||
return NextResponse.json(
|
||||
{ error: '请填写 API Key 或用户名密码' },
|
||||
{ error: '请填写 API Key 或用户名' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
@@ -69,9 +69,9 @@ export async function POST(request: NextRequest) {
|
||||
const client = new EmbyClient(testConfig);
|
||||
|
||||
// 如果使用用户名密码,先认证
|
||||
if (!ApiKey && Username && Password) {
|
||||
if (!ApiKey && Username) {
|
||||
try {
|
||||
await client.authenticate(Username, Password);
|
||||
await client.authenticate(Username, Password || '');
|
||||
} catch (error) {
|
||||
return NextResponse.json(
|
||||
{ success: false, message: 'Emby 认证失败: ' + (error as Error).message },
|
||||
|
||||
@@ -115,9 +115,9 @@ export class EmbyClient {
|
||||
// 如果有 AuthToken,假设它是有效的
|
||||
if (this.authToken) return;
|
||||
|
||||
// 如果有用户名和密码,自动认证
|
||||
if (this.username && this.password) {
|
||||
const authResult = await this.authenticate(this.username, this.password);
|
||||
// 如果有用户名,自动认证(密码可选)
|
||||
if (this.username) {
|
||||
const authResult = await this.authenticate(this.username, this.password || '');
|
||||
this.authToken = authResult.AccessToken;
|
||||
this.userId = authResult.User.Id;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user