2013-07-23 5 views
6

워크 플로를 제대로 이해하지 못하는 것 같습니다. 아파치 시로 (Apache Shiro)와 스톰 패스 (Stormpath)를 사용하여 스칼라에 웹 서비스를 작성하고 있습니다. 내 사용자 인증 프로세스는 다음과 같습니다Sciro + Akka + Spray 환경에서 Shiro 작품을 만들 수있는 방법

1), POST 요청에서 사용자 데이터를 가져 Stormpath 그것을 확인하고 모든 일부 페이지에 대한 좋은 리디렉션 경우 : 로그에서

pathPrefix("api") { 
    path("login") { 
    post { 
     AuthToken.fromRequest { (token: AuthToken) => 
     stormpathAuth(token) { subj => 
      log.info("Subj {}", subj.getPrincipal.toString) 
      redirect("/some/page", StatusCodes.Found) 
     } 
     } 
    } 
    } 

가 좋아, 시로 반환 Stormpath 계정이있는 정확한 제목. 다음으로 코드에서 사용하는, 제목을 추출 할 :

pathPrefix("some") { 
    loggedInUser { subject => 
    path("page") { 
     get { 
     complete { 
      html.render(Page.model) 
     } 
     } 
    } ..... other routes 


loggedInUser 지침이 될 추출이 로그인 폼으로 리디렉션 기타의 방법으로 인증 않다면 확인해야합니다. 문제는 로그에서 항상 올바른 계정을 표시하지만 로그인 양식으로 리디렉션된다는 것입니다.

업데이트

사실 스프레이는 Akka 위에 구축입니다. 그래서 문제는 getSubject 구현 뒤에 있으며 현재 ThreadLocal 환경에 의존한다고 생각합니다. Shiro + Akka 주제를 검색했지만 유용한 정보를 찾지 못했습니다.

+1

[Shiro Stormpath plugin] (https://github.com/stormpath/stormpath-shiro/wiki)을 사용하고 있습니까? –

+1

또한 Servlet 컨테이너 또는 W/Play에서 실행 중입니까? ? –

+0

@LesHazlewood 예 사용자 인증을 위해 Stormpath 플러그인을 사용하고 있습니다. 아니요, [스프레이 툴킷] (http://spray.io/), 스프레이 캔 및 스프레이 라우팅으로 내 서버 및 클라이언트 측을 빌드했습니다. – 4lex1v

답변

6

확실히 가능하지만 메시지를 처리 ​​할 때 Subject을 Akka 구성 요소 (액터)가 사용할 수 있도록해야합니다.

내가 Akka의 아키텍처 (배우/메시징 모델)에 대해 잘 알고,하지만 나 자신 Akka 사용하지 않은, 그래서 최선의 추측 응답으로 다음과 같은하시기 바랍니다 :

전통적인 시로 기반 응용 프로그램에서 및/무언가은 현재 발신자 및/또는 요청을 반영한 Subject 인스턴스를 작성한 다음 현재 실행중인 Thread에 바인딩합니다. 이렇게하면 해당 스레드가 실행되는 동안 후속 호출이 SecurityUtils.getSubject()으로 올바르게 작동합니다. 이 내용은 모두 Shiro's Subject documentation에 문서화되어 있습니다 (Subject.Builder스레드 연결 섹션 참조).

웹 응용 프로그램에서 예를 들어, ShiroFilterthis setup/bind/unbind logic automatically ServletRequest입니다. Akka 기반 응용 프로그램에서 무언가 (프레임 워크의 코드 또는 구성 요소)가 동일한 설치/바인딩/바인딩 해제 논리를 수행 할 것으로 의심됩니다.

Akka와 함께, 위의 문서에서 다루는 것처럼 전통적인 스레드 기반 접근 방식을 사용할 수 있다고 확신합니다 (저는 Play! 사용자가 성공한 것으로 생각합니다). 그러나 또 다른 흥미로운 접근 방식은 Akka 불변의 메시지와 함께 사용할 수 있습니다 메시지가 구축되면, 당신은 시로 PrincipalCollection과 같은 것들과 메시지 (예 : 메시지 '헤더')에 따라 관련 정보를 첨부 할 수 있습니다

  • 인증 상태 (인증 여부) 및 기타 (runAs 상태, 무엇이든).

  • 메시지가 수신되면 해당 정보는 Subject 인스턴스를 만들기 위해 Subject.Builder에 대한 입력으로 사용되며 해당 Subject 인스턴스는 메시징 처리 중에 사용됩니다. Shiro Subject 인스턴스는 매우 가볍고 요청 당 생성되거나 파괴 될 것으로 예상되므로 (또는 필요한 경우 요청 당 여러 번) 작성자 오버 헤드에 대해 걱정할 필요가 없습니다.

  • Subject이 빌드되면 현재 실행중인 스레드를 바인드 한 다음 바인딩 해제하거나 메시지를 처리하는 각 액터가 '프레임 워크'방식으로 동일한 로직을 통과 할 수 있습니다. 이 후자의 접근 방식은 스레드 상태가 아니라 메시지 수준에서 주체 상태가 유지되므로 스레드 바인딩이 필요하지 않습니다.

이 대안의 증거 (비 스레드 기반) 방식으로 ActiveMQ 대한 예정된 Shiro plugin 시로 상태가 아닌 스레드를 저장하는 접속 상태를 이용한다. 마찬가지로 메시지 상태도 쉽게 사용할 수 있습니다.

스레드 기반 방식이 아닌 경우, 다운 스트림 호출자는 Subject 인스턴스를 얻기 위해 SecurityUtils.getSubject()을 호출 할 수 없습니다. 그들은 다른 '틀에 박힌'방식으로 그것을 얻어야 할 것입니다.

다시 말해서 Akka를 사용하지 않고도 Akka와 같은 메시징 환경에서 이것이 어떻게 작동하는지에 대한 최선의 노력 분석입니다. 바라건대 이것으로 유스 케이스와 관련된 방식으로이 문제를 해결할 수있는 충분한 정보를 얻을 수 있기를 바랍니다.

3

다음 질문에 대한 답변은 동일한 문제가 발생했을 때 매우 유용했습니다. 주요 목표는 Les Hazlewood의 제안 된 구현에 대한 추가 정보를 제공하는 것입니다. 정보의 또 다른 좋은 대안 소스는이 주제입니다. https://groups.google.com/forum/#!topic/spray-user/wpiG4SREpl0

Shiro는 현재 스레드 기반으로, 주제 정보를 현재 스레드에 바인드합니다. 이것은 Akka가 운영자와 작업자의 스레드 풀을 사용하기 때문에 발생하는 문제입니다.

스레드가 재사용됨에 따라 하나의 요청에서 다른 스레드로 주제가 누출되어 인증되지 않은 요청이 인증 된 프로세스와 반대의 프로세스가됩니다.

대단히 좋습니다. 문제의 가능한 해결책은 스레드 바인딩을 포기하고 Akka 메시지에 제목을 저장하는 것입니다. 이것이 작동하려면 Shiro의 SecurityUtils에 제공된 정적 메서드를 사용할 수 없다는 것을 의미합니다. 조작은 주제에서 직접 수행해야합니다. 또한이 제목은 Subject.Builder를 사용하여 작성해야합니다.

이를 위해 당신은 주제와

case class ActorMessage(subject:Subject, value: Any) 


object MessageSender { 

def ? (actorRef: ActorRef, message: Any)(implicit subject: Subject): Future[Any] = { 
    val resultFuture = if (!message.isInstanceOf[ActorMessage]) { 
     val actorMessage = ActorMessage(subject, message) 
     actorRef ask actorMessage 
    } else actorRef ask message 

    for (result <- resultFuture) yield { 
    if (result.isInstanceOf[ActorMessage]) { 
     val actorMessageResp = result.asInstanceOf[ActorMessage] 
     actorMessageResp.value 
    } else result 
    } 
} 

} 

을 메시지를 포장 할 수 있으며이 메시지를 수신 할 때 배우에 그들을 풀다. 또는 요청 항목 액터 인 경우 제목을 초기화합니다. 이제

abstract class ShiroActor extends Actor { 

implicit var shiroSubject: Subject = (new Subject.Builder).buildSubject 

override def aroundReceive(receive: Actor.Receive, msg: Any): Unit = { 
    if (msg.isInstanceOf[ActorMessage]) { 
     val actorMessage = msg.asInstanceOf[ActorMessage] 
     shiroSubject = actorMessage.subject 
     receive.applyOrElse(actorMessage.value, unhandled) 
    } else { 
    shiroSubject = (new Subject.Builder).buildSubject 
     receive.applyOrElse(msg, unhandled) 
    } 
    } 

} 

는 ShiroActor을 확장하고 요청하거나 방법을 말할 대신 ActorRef의, 당신은 MessageSender을 사용해야합니다 배우 사이에 메시지를 교환해야합니다 구현 배우를 사용할 수 있습니다.

제목, checkpermissions, 역할 등에 로그인하려면 배우에서 사용할 수있는 제목을 사용할 수 있습니다.이처럼

shiroSubject.login(new AuthenticationToken(principal, credentials)) 

이 로그인 요청 항목 배우에서 수행되고 피사체가 바로 이후 배우에 대한 사용 권한을 검사 할 공유 가정합니다. 그러나 액티비티의 shiroSubject를 양방향으로 업데이트하는 것이 쉬운 적응이라고 확신합니다.

이 두 프레임 워크 간의 통합 예제를 찾는 것이 거의 불가능한 것처럼 보이기 때문에 이것이 유용 할 것입니다.