Authentication 如何使用Guardian通过api和会话同时对用户进行身份验证?

Authentication 如何使用Guardian通过api和会话同时对用户进行身份验证?,authentication,cookies,elixir,phoenix-framework,Authentication,Cookies,Elixir,Phoenix Framework,我正在尝试通过api对用户进行身份验证,但我也希望确保他们在刷新页面时保持身份验证 Guardian.Plug.sign_-in似乎适合在cookie中存储用户身份验证,但当我通过api进行身份验证时,cookie没有设置 这确实有效: conn |> Guardian.Plug.sign_in(user) |> redirect(to: root_path(conn, :index)) 按以下顺序使用这些管道: pipeline :browser do plug :

我正在尝试通过api对用户进行身份验证,但我也希望确保他们在刷新页面时保持身份验证

Guardian.Plug.sign_-in似乎适合在cookie中存储用户身份验证,但当我通过api进行身份验证时,cookie没有设置

这确实有效:

conn
|> Guardian.Plug.sign_in(user)
|> redirect(to: root_path(conn, :index))
按以下顺序使用这些管道:

  pipeline :browser do
     plug :accepts, ["html"]
     plug :fetch_session
     plug :fetch_flash
     plug :protect_from_forgery
     plug :put_secure_browser_headers
   end

   pipeline :browser_session do
     plug Guardian.Plug.VerifySession
     plug Guardian.Plug.LoadResource
   end
  pipeline :api do
     plug :accepts, ["json"]
     plug Guardian.Plug.VerifyHeader
     plug Guardian.Plug.LoadResource
  end

  pipeline :api_session do
     plug :fetch_session
     plug :fetch_flash
     plug :put_secure_browser_headers
     plug Guardian.Plug.VerifySession
  end
这并不是:

conn
|> Guardian.Plug.sign_in(user)
|> render("session.json")
按以下顺序使用这些管道:

  pipeline :browser do
     plug :accepts, ["html"]
     plug :fetch_session
     plug :fetch_flash
     plug :protect_from_forgery
     plug :put_secure_browser_headers
   end

   pipeline :browser_session do
     plug Guardian.Plug.VerifySession
     plug Guardian.Plug.LoadResource
   end
  pipeline :api do
     plug :accepts, ["json"]
     plug Guardian.Plug.VerifyHeader
     plug Guardian.Plug.LoadResource
  end

  pipeline :api_session do
     plug :fetch_session
     plug :fetch_flash
     plug :put_secure_browser_headers
     plug Guardian.Plug.VerifySession
  end

我无法猜测为什么一个有效,另一个无效,因为它的行为和本质上似乎是相同的。

如果您想使用相同的身份验证来管理API和浏览器,那么只需使用浏览器身份验证即可。例如,如果您的端点是graphql中间件,则必须对NetworkLayer进行如下配置:

Relay.injectNetworkLayer(
  new Relay.DefaultNetworkLayer('http://example.com/graphql', {
    credentials: 'same-origin',
  })
);
function requireAuth(nextState, replace) {
  if (!auth.loggedIn()) {
    replace({
      pathname: '/session/new',
      state: { nextPathname: nextState.location.pathname }
    })
  }
}

ReactDOM.render(
  <Router history={browserHistory}
    render={applyRouterMiddleware(useRelay)}
    environment={Relay.Store}>
    <Route path="/" component={Hello}/>
    <Route path="/session/new" component={Login}/>
    <Route path="/admin" component={AdminLayout} onEnter={requireAuth}>
      <IndexRoute component={HelloAdmin}/>
      <Route path="star-wars" component={StarWarsApp} queries={StarWarsQueries}/>
      <Route path="graphiql" component={GraphiQL} />
    </Route>
  </Router>,
  document.getElementById('react-root')
);
这样,您的中继应用程序将使用与加载/刷新页面时相同的会话。这和老式的Ajax一样

另一方面,如果所有前端都基于浏览器中呈现的Javascript客户端(即:React&Relay),那么您可以使用Phoenix控制器仅呈现Javascript将执行的页面,并完全依赖JWT。例如,使用react router,您可以执行以下操作:

Relay.injectNetworkLayer(
  new Relay.DefaultNetworkLayer('http://example.com/graphql', {
    credentials: 'same-origin',
  })
);
function requireAuth(nextState, replace) {
  if (!auth.loggedIn()) {
    replace({
      pathname: '/session/new',
      state: { nextPathname: nextState.location.pathname }
    })
  }
}

ReactDOM.render(
  <Router history={browserHistory}
    render={applyRouterMiddleware(useRelay)}
    environment={Relay.Store}>
    <Route path="/" component={Hello}/>
    <Route path="/session/new" component={Login}/>
    <Route path="/admin" component={AdminLayout} onEnter={requireAuth}>
      <IndexRoute component={HelloAdmin}/>
      <Route path="star-wars" component={StarWarsApp} queries={StarWarsQueries}/>
      <Route path="graphiql" component={GraphiQL} />
    </Route>
  </Router>,
  document.getElementById('react-root')
);

然后你就可以在后台使用Guardian的东西了。请记住,在这个完整的API选项中,呈现登录页面的逻辑将在前端完全实现。

请注意:由于XSS,使用本地存储作为会话令牌是一个糟糕的想法