> php教程 > PHP开发 > 본문

Laravel의 기본 세션 미들웨어 확장으로 인한 세션 쓰기 실패 문제 분석

高洛峰
풀어 주다: 2016-12-27 10:04:12
원래의
1072명이 탐색했습니다.

최근 프로젝트 개발 요구로 인해 모바일 클라이언트와 웹 클라이언트는 통합된 인터페이스 세트를 사용하여 다양한 상황에서 세션이 정상적이고 호환될 수 있도록 SessionID를 얻는 방법을 변경하려고 합니다. 기본적으로 모든 웹사이트는 HTTP 요청의 Header 헤더에 있는 Cookie를 통해 구현되며, Cookie에 지정된 SessionID는 서버 측의 해당 데이터와 연결되어 세션 기능을 구현합니다.

단, 모바일 클라이언트의 경우 원래 쿠키가 지원되지 않거나 플랫폼 요구에 따라 차단될 수 있으므로 개발에서는 SessionID를 식별하기 위해 요청 헤더 X-Session-Token을 추가해야 합니다. Laravel 프레임워크에서 세션 초기화, 읽기 및 시작은 모두 IlluminateSessionMiddlewareStartSession 미들웨어를 통해 구현됩니다. 이 미들웨어에는 getSession이라는 핵심 메소드가 있으며, 이 메소드는 SessionId를 얻고 세션 데이터를 복원하는 데 사용할 자격 증명을 Session 구성 요소에 알려주는 것입니다.

이 미들웨어는 app/Http/Kernel.php 파일에 등록되어 있습니다.

미들웨어를 상속받기 위해 새 클래스를 생성하고 app/Http/Kernel.php 아래의 등록 위치를 교체했습니다. 원래 getSession 메소드 소스 코드는 다음과 같습니다.

public function getSession(Request $request)
{
$session = $this->manager->driver();
$session->setId($request->cookies->get($session->getName()));
return $session;
}
로그인 후 복사

In In 새로운 미들웨어를 다음과 같이 변경했습니다.

public function getSession(Request $request)
{
$session = $this->manager->driver();
// 判断是否是接口访问并根据实际情况选择 SessionID 的获取方式
if ($request->headers->has('x-session-token')) {
$sessionId = $request->headers->has('x-session-token');
} else {
$sessionId = $request->cookies->get($session->getName());
}
$session->setId($sessionId);
return $session;
}
로그인 후 복사

하지만 문제도 발생했습니다. . .

수정 후 메인 개발 브랜치로 병합하기 전에 단위 테스트를 실행해야 하는 경우가 많습니다. 안타깝게도 이번에는 통과한 사례에서 오류가 발생했습니다. CSRF 구성 요소에서 토큰 오류를 보고했습니다. 여기서 제공하는 토큰은 평소와 다르지 않으며 세션에 문제가 있는 것 같습니다.

미들웨어 코드를 수정해도 프레임워크에는 전혀 영향이 없다고 할 수 있다는 점은 주목할 만합니다. 실제로는 제가 작성한 미들웨어 코드를 에 수정했기 때문입니다. 상속된 미들웨어 코드도 도움이 되지 않지만 이상하게도 미들웨어를 원래 미들웨어로 다시 전환한 후에는 이 문제가 발생하지 않습니다.

그래서 정상 조건과 비정상 조건에서 코드를 실행하고 핵심 지점에 중단점을 두고 디버깅한 결과 미들웨어의 중요한 속성인 $sessionHandled에 문제가 있다는 것을 발견했습니다. 이전 상황의 원인이 됩니다. 중요한 점은 미들웨어가 시작될 때 핸들 메소드가 사용된다는 것입니다. 세션 미들웨어의 경우 핸들 메소드 코드의 첫 번째 줄은 다음과 같습니다.

$this->sessionHandled = true;

흥미롭네요. . .

우리는 알고 있습니다. Laravel 프레임워크의 특징은 구성 요소 간의 느슨한 결합을 보장하기 위해 다양한 종속성 주입을 구현하기 위해 프레임워크의 다양한 클래스를 초기화하는 역할을 하는 IoC 컨테이너입니다. 미들웨어도 예외는 아닙니다. 싱글톤과 일반 인스턴스의 가장 큰 차이점은 몇 번을 생성하더라도 항상 동일하며 인스턴스의 속성이 초기화되지 않는다는 점을 알아야 합니다. 따라서 문제가 없습니다. 미들웨어는 싱글톤이어야 하며, 제가 직접 만든 미들웨어는 일반 클래스의 인스턴스일 뿐입니다. 하지만 무슨 일이 일어나고 있고 왜 일어나는지 알려면 내 생각을 확인해야 합니다(사실 해결책은 이미 생각해 뒀으며 이에 대해서는 나중에 논의하겠습니다).

그럼 문제는 대충 미들웨어 초기화인데 힘내서 라라벨의 스타트업 코드를 좀 더 살펴봐야겠네요. 여기서 핵심은 IlluminatePipelinePipeline이라는 클래스에 있습니다.

이 클래스에는 send, through 및 then 세 가지 중요한 메소드가 있습니다. 그렇다면 모든 것을 시작하는 열쇠는 어디에 있습니까? 이 클래스는 주로 여러 프레임워크 시작 단계를 지속적으로 실행하는 것입니다. 첫 번째는 처리 프로세스에 필요한 구성 요소(요청 및 미들웨어)를 초기화하고 두 번째는 이러한 처리 구성 요소로 구성된 스택을 통해 요청을 전달하는 것입니다. 미들웨어 및 라우팅 디스패치 구성 요소)), 마지막으로 처리 결과(응답)를 반환합니다.

이것이 Laravel Http 부분의 핵심이라고 할 수 있습니다(뭐, 원래는 Kernel 입니다). 그러면 이전 문제는 Pipeline의 then 메소드와 그것이 호출하는 getSlice 메소드에 있습니다. getSlice 메소드를 직접 관찰하면 이것이 처리 스택을 생성하고 Middleware 클래스를 인스턴스화하는 역할을 담당한다는 것을 알 수 있습니다.

protected function getSlice()
{
return function ($stack, $pipe) {
return function ($passable) use ($stack, $pipe) {
if ($pipe instanceof Closure) {
return call_user_func($pipe, $passable, $stack);
} else {
list($name, $parameters) = $this->parsePipeString($pipe);
return call_user_func_array([$this->container->make($name), $this->method],
array_merge([$passable, $stack], $parameters));
}
};
};
}
로그인 후 복사

$this->container->make($name)는 단순히 make라는 미들웨어 클래스를 초기화한다는 의미입니다. 싱글톤이 아닌 경우 반복적으로 사용됩니다. 새로운 속성이 생성되어 이전 속성이 초기화됩니다.

그러면 해결책은 확실합니다. 싱글톤으로 만드세요.

app/Providers/AppServiceProvider.php의 등록 메소드에 다음 코드 줄을 추가하여 이전 문제를 해결했습니다.

$this->app->singleton(SessionStart : :class); // SessionStart는 내 미들웨어 클래스의 이름입니다

위 내용은 Laravel의 기본 세션 미들웨어 확장으로 인해 발생하는 세션 쓰기 실패 문제에 대한 전체 분석을 소개합니다.

Laravel의 기본 세션 미들웨어 확장으로 인한 세션 쓰기 실패 문제 분석에 대한 더 많은 관련 기사를 보려면 PHP 중국어 웹사이트를 주목하세요!

원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 추천
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿