无需用户越来越ROLE_USER FOSUserbundle +附加HTTP认证 [英] FOSUserbundle + Additional HTTP auth without user getting ROLE_USER
问题描述
我与Symfony2的安全系统中的小问题。这是我需要实现:
I have a "little" problem with the Symfony2 security system. This is what I need to achieve:
- /需要一个HTTP认证之前的任何页面都可以看到。我要保护整个页面以恒定的用户名/密码对。用户输入正确的对后,他应该是一个来宾(而不是ROLE_USER)UND能够通过FOSUserBundle形式登录
- / API通过HTTP需要一个单独的登录身份验证,独立于FOSUserBundle和其他HTTP认证
我已经成功地提供了API单独的登录。这是我的完整security.yml:
I already managed to provide a separate login for the API. This is my complete security.yml:
security:
encoders:
FOS\UserBundle\Model\UserInterface: sha512
Symfony\Component\Security\Core\User\User: plaintext
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
in_memory_http:
memory:
users:
User1: { password: PW1, roles: ROLE_HTTP }
in_memory_api:
memory:
users:
User2: { password: PW2, roles: ROLE_API }
fos_userbundle:
id: fos_user.user_provider.username_email
firewalls:
api:
pattern: ^/api
http_basic:
provider: in_memory_api
realm: "API login"
http:
pattern: ^/
provider: in_memory_http
http_basic:
realm: "Hello"
context: primary_auth
main:
pattern: ^/
form_login:
provider: fos_userbundle
login_path: fos_user_security_login
csrf_provider: form.csrf_provider
check_path: fos_user_security_check
logout:
path: fos_user_security_logout
target: home
anonymous: true
context: primary_auth
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
security: false
secured_area:
anonymous: ~
access_control:
- { path: ^/api, roles: ROLE_API }
- { path: ^/user/login.html, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/user/logout.html, roles: IS_AUTHENTICATED_REMEMBERED }
本作品近百如预期,但遗憾的是没有完全...
在/ API部分的工作方式类似,我想它的工作。无事可做在这里,我希望。
This works nearly as expected, but unfortunately not completely... The /api part works like I wanted it to work. Nothing to do here, I hope.
但是,当我浏览到/,进入用户1 / PW1和发送的凭据,我可以访问的页面,就像预期。唯一的问题是,用户1被登录!但我想用户1不能像一个正常的用户操作。他应该只需要使用普通的登录表单和其余/除/ API的。我甚至不能注销该用户。如果我浏览到/user/login.html而user1的登录(由于所需的HTTP验证),并输入一个真实的fosuserbundle用户的有效的用户数据,我得到:你必须配置检查路径被防火墙处理使用form_login在安全的防火墙配置。
But when I navigate to /, enter User1/PW1 and send the credentials, I get access to the page, just like expected. The only problem is that the User1 gets logged in! But I want User1 not to be handled like a normal user. He should just be required to access the normal login form and the rest of / except of /api. I can't even log out this user. If I navigate to /user/login.html while User1 is logged in (due to the required http auth) and enter valid user data of a real fosuserbundle user, I get: "You must configure the check path to be handled by the firewall using form_login in your security firewall configuration."
如果我要退出,我得到:你必须激活您的安全防火墙配置注销。
If I want to log out, I get: "You must activate the logout in your security firewall configuration."
我要的是怎样的一个两步验证。
首先HTTP认证,那么FOSUserBundle形式。
What I want is kind of a two step authentication. First HTTP Auth, then the FOSUserBundle form.
有人可以帮我吗? :)该文档是不是很好在这一点上...
Can somebody help me? :) The documentation is not very good at this point...
推荐答案
所以.....
几个小时的纯疼痛后,我放弃了与Symfony2的安全组件尝试它。我也没能实现我想要的东西与Apache(尝试SetEnvIf之后和FilesMatch)。
After several hours of pure pain I gave up on trying it with the Symfony2 Security Component. I also did not manage to realize what I want with Apache (Tried SetEnvIf and FilesMatch).
所以我写了一个请求监听器我想要做什么。如果有人有同样的问题,这里是我的解决方案!
So I wrote a request listener that does what I want. If anybody has the same problem, here is my solution!
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpFoundation\Response;
class RequestListener
{
/**
* Returns true iff the specified $password belongs to the $user and the $user has access to the specified $area
*/
private function hasAccess($user, $password, $area) {
$users = array("User1" => array("password" => "PW1",
"areas" => array("portal")),
"User2" => array("password" => "PW2",
"areas" => array("API", "portal"))
);
return $user
&& array_key_exists($user, $users)
&& $users[$user]["password"] == $password
&& in_array($area, $users[$user]["areas"]);
}
/**
* Extracts the area out of the $path
*/
public function getArea($path) {
if (substr($path, 0, 4) == "/api") {
return "API";
} else {
return "portal";
}
}
/**
* Service handler
*/
public function onKernelRequest(GetResponseEvent $event) {
$request = $event->getRequest();
# $path cointains the path to the virtual resource the user requested!
# If the user calls app_dev.php/api/users, then $path is "/api/users"
# If the user calls app.php/api/users, then $path is "/api/users"
# If the user calls /api/users, then $path is "/api/users"
# If the user calls /app_dev.php, then $path is "/"
# If the user calls /, then $path is "/"
# and so on
#
# ==> $path abstracts the front controller away
$path = $request->getPathInfo();
$area = $this->getArea($path);
# $user, $password are null if no AUTH data is sent
$user = $request->server->get("PHP_AUTH_USER");
$password = $request->server->get("PHP_AUTH_PW");
# If the user has no access, he must log in as another user
if (!$this->hasAccess($user, $password, $area)) {
# In case the response already exists (in most cases not) we use it and modify it
$response = $event->hasResponse() ? $event->getResponse() : new Response();
$response->setStatusCode(Response::HTTP_UNAUTHORIZED); # Code 401
$response->headers->set("WWW-Authenticate", "Basic realm=\"".$area."\"");
$response->setContent("Please provide valid data");
$response->send();
die(); # To make sure the page is not shown!
}
}
}
现在一切似乎工作...
Now everything seems to work...
这篇关于无需用户越来越ROLE_USER FOSUserbundle +附加HTTP认证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!