React Native + Redux 基础认证
React Native + Redux basic authentication
我正在寻找一种方法来为我的本机反应应用程序创建基本身份验证。
我找不到任何关于 react-native 应用程序的好例子。
- 为了登录,应用程序将 email/password + clientSecret 发送到我的服务器
- 如果OK,服务器returns accessToken + refreshToken
- 用户已登录,所有其他请求都包含带有 accessToken 的承载。
- 如果 accessToken 过期,应用会自动使用 refreshToken 请求一个新的。
- 用户一直保持登录状态,状态应该保存在phone.
最好的方法是什么?
谢谢。
我还没有看到太多这方面的例子,我认为这绝对需要更多的报道。我自己还没有实现身份验证,否则我会向您指出一些代码示例。但我可以向您指出我收集的几个链接,它们可能会帮助您朝着正确的方向前进...
无论您如何执行身份验证,您都需要安全地存储您的访问、刷新和秘密令牌。在 iOS 上,我相信您会使用 keychain and for Android it looks like KeyStore is the way. You may find oblador/react-native-keychain helpful, though it doesn't yet support android it looks like it may support android soon 来做到这一点。
当应用与强制执行某种形式的身份验证的 HTTP API 通信时,应用通常遵循以下步骤:
- 应用程序未通过身份验证,因此我们提示用户登录。
- 用户输入他们的凭据(用户名和密码),然后点击提交。
- 我们将这些凭据发送到 API,并检查响应:
- 成功时(200 - OK):我们缓存身份验证令牌/哈希,因为我们将在每个后续 请求中使用此令牌/哈希。
- 如果令牌/哈希在任何后续 API 请求期间不起作用(401 - 未经授权),我们需要使哈希/令牌无效并提示用户重新登录。
- 或者,在失败时(401 - 未经授权):我们向用户显示一条错误消息,提示他们 re-enter 他们的凭据。
正在登录
根据上面定义的工作流程,我们的应用程序首先显示登录表单,步骤 2 在用户点击调度 login
的登录按钮时启动下面的动作创建者:
/// actions/user.js
export function login(username, password) {
return (dispatch) => {
// We use this to update the store state of `isLoggingIn`
// which can be used to display an activity indicator on the login
// view.
dispatch(loginRequest())
// Note: This base64 encode method only works in NodeJS, so use an
// implementation that works for your platform:
// `base64-js` for React Native,
// `btoa()` for browsers, etc...
const hash = new Buffer(`${username}:${password}`).toString('base64')
return fetch('https://httpbin.org/basic-auth/admin/secret', {
headers: {
'Authorization': `Basic ${hash}`
}
})
.then(response => response.json().then(json => ({ json, response })))
.then(({json, response}) => {
if (response.ok === false) {
return Promise.reject(json)
}
return json
})
.then(
data => {
// data = { authenticated: true, user: 'admin' }
// We pass the `authentication hash` down to the reducer so that it
// can be used in subsequent API requests.
dispatch(loginSuccess(hash, data.user))
},
(data) => dispatch(loginFailure(data.error || 'Log in failed'))
)
}
}
上面的函数中有很多代码,但请放心
大部分代码都在清理响应,可以抽象掉。
我们做的第一件事是发送一个操作 LOGIN_REQUEST
,它更新我们的商店并让我们知道用户 isLoggingIn
。
dispatch(loginRequest())
我们用它来显示 activity 指示器( 旋转轮,"Loading...",等等 ),并禁用我们的登录按钮登录查看。
接下来我们对http basic auth的用户名和密码进行base64编码,传递给request的headers.
const hash = new Buffer(`${username}:${password}`).toString('base64')
return fetch('https://httpbin.org/basic-auth/admin/secret', {
headers: {
'Authorization': `Basic ${hash}`
}
/* ... */
如果一切顺利,我们将发送一个 LOGIN_SUCCESS
操作,这将导致我们在我们的商店中获得身份验证 hash
,我们将在后续请求中使用它。
dispatch(loginSuccess(hash, data.user))
另一方面,如果出现问题,我们也想让用户知道:
dispatch(loginFailure(data.error || 'Log in failed')
loginSuccess
、loginFailure
和 loginRequest
动作创建器相当通用,并不真正保证代码示例。参见:https://github.com/peterp/redux-http-basic-auth-example/blob/master/actions/user.js)
减速机
我们的reducer也是典型的:
/// reducers/user.js
function user(state = {
isLoggingIn: false,
isAuthenticated: false
}, action) {
switch(action.type) {
case LOGIN_REQUEST:
return {
isLoggingIn: true, // Show a loading indicator.
isAuthenticated: false
}
case LOGIN_FAILURE:
return {
isLoggingIn: false,
isAuthenticated: false,
error: action.error
}
case LOGIN_SUCCESS:
return {
isLoggingIn: false,
isAuthenticated: true, // Dismiss the login view.
hash: action.hash, // Used in subsequent API requests.
user: action.user
}
default:
return state
}
}
后续 API 个请求
现在我们的商店中有一个身份验证散列,我们可以将它传递到后续请求的 headers。
在下面的示例中,我们正在为经过身份验证的用户获取好友列表:
/// actions/friends.js
export function fetchFriends() {
return (dispatch, getState) => {
dispatch(friendsRequest())
// Notice how we grab the hash from the store:
const hash = getState().user.hash
return fetch(`https://httpbin.org/get/friends/`, {
headers: {
'Authorization': `Basic ${hash}`
}
})
.then(response => response.json().then(json => ({ json, response })))
.then(({json, response}) => {
if (response.ok === false) {
return Promise.reject({response, json})
}
return json
})
.then(
data => {
// data = { friends: [ {}, {}, ... ] }
dispatch(friendsSuccess(data.friends))
},
({response, data}) => {
dispatch(friendsFailure(data.error))
// did our request fail because our auth credentials aren't working?
if (response.status == 401) {
dispatch(loginFailure(data.error))
}
}
)
}
}
您可能会发现大多数 API 请求通常会发送与上述相同的 3 个操作:API_REQUEST
、API_SUCCESS
和 API_FAILURE
,因此大多数请求/响应代码可以被推送到 Redux 中间件。
我们从商店获取哈希身份验证令牌并设置请求。
const hash = getState().user.hash
return fetch(`https://httpbin.org/get/friends/`, {
headers: {
'Authorization': `Basic ${hash}`
}
})
/* ... */
如果 API 响应带有 401 状态代码,那么我们必须从存储中删除哈希,并再次向用户显示登录视图。
if (response.status == 401) {
dispatch(loginFailure(data.error))
}
我已经笼统地回答了这个问题并且只处理 http-basic-auth。
我认为这个概念可能保持不变,你将在商店中推送 accessToken
和 refreshToken
,并在后续请求中提取它。
如果请求失败,则您必须发送另一个更新 accessToken 的操作,然后撤回原始请求。
实际上我正在制作一个视频教程系列,它至少可以回答您提出的一些问题。可以在此处找到该视频以及文字记录和示例代码:http://codecookbook.co/post/how-to-build-a-react-native-login-form-with-redux-pt1/
我正在寻找一种方法来为我的本机反应应用程序创建基本身份验证。 我找不到任何关于 react-native 应用程序的好例子。
- 为了登录,应用程序将 email/password + clientSecret 发送到我的服务器
- 如果OK,服务器returns accessToken + refreshToken
- 用户已登录,所有其他请求都包含带有 accessToken 的承载。
- 如果 accessToken 过期,应用会自动使用 refreshToken 请求一个新的。
- 用户一直保持登录状态,状态应该保存在phone.
最好的方法是什么?
谢谢。
我还没有看到太多这方面的例子,我认为这绝对需要更多的报道。我自己还没有实现身份验证,否则我会向您指出一些代码示例。但我可以向您指出我收集的几个链接,它们可能会帮助您朝着正确的方向前进...
无论您如何执行身份验证,您都需要安全地存储您的访问、刷新和秘密令牌。在 iOS 上,我相信您会使用 keychain and for Android it looks like KeyStore is the way. You may find oblador/react-native-keychain helpful, though it doesn't yet support android it looks like it may support android soon 来做到这一点。
当应用与强制执行某种形式的身份验证的 HTTP API 通信时,应用通常遵循以下步骤:
- 应用程序未通过身份验证,因此我们提示用户登录。
- 用户输入他们的凭据(用户名和密码),然后点击提交。
- 我们将这些凭据发送到 API,并检查响应:
- 成功时(200 - OK):我们缓存身份验证令牌/哈希,因为我们将在每个后续 请求中使用此令牌/哈希。
- 如果令牌/哈希在任何后续 API 请求期间不起作用(401 - 未经授权),我们需要使哈希/令牌无效并提示用户重新登录。
- 或者,在失败时(401 - 未经授权):我们向用户显示一条错误消息,提示他们 re-enter 他们的凭据。
- 成功时(200 - OK):我们缓存身份验证令牌/哈希,因为我们将在每个后续 请求中使用此令牌/哈希。
正在登录
根据上面定义的工作流程,我们的应用程序首先显示登录表单,步骤 2 在用户点击调度 login
的登录按钮时启动下面的动作创建者:
/// actions/user.js
export function login(username, password) {
return (dispatch) => {
// We use this to update the store state of `isLoggingIn`
// which can be used to display an activity indicator on the login
// view.
dispatch(loginRequest())
// Note: This base64 encode method only works in NodeJS, so use an
// implementation that works for your platform:
// `base64-js` for React Native,
// `btoa()` for browsers, etc...
const hash = new Buffer(`${username}:${password}`).toString('base64')
return fetch('https://httpbin.org/basic-auth/admin/secret', {
headers: {
'Authorization': `Basic ${hash}`
}
})
.then(response => response.json().then(json => ({ json, response })))
.then(({json, response}) => {
if (response.ok === false) {
return Promise.reject(json)
}
return json
})
.then(
data => {
// data = { authenticated: true, user: 'admin' }
// We pass the `authentication hash` down to the reducer so that it
// can be used in subsequent API requests.
dispatch(loginSuccess(hash, data.user))
},
(data) => dispatch(loginFailure(data.error || 'Log in failed'))
)
}
}
上面的函数中有很多代码,但请放心 大部分代码都在清理响应,可以抽象掉。
我们做的第一件事是发送一个操作 LOGIN_REQUEST
,它更新我们的商店并让我们知道用户 isLoggingIn
。
dispatch(loginRequest())
我们用它来显示 activity 指示器( 旋转轮,"Loading...",等等 ),并禁用我们的登录按钮登录查看。
接下来我们对http basic auth的用户名和密码进行base64编码,传递给request的headers.
const hash = new Buffer(`${username}:${password}`).toString('base64')
return fetch('https://httpbin.org/basic-auth/admin/secret', {
headers: {
'Authorization': `Basic ${hash}`
}
/* ... */
如果一切顺利,我们将发送一个 LOGIN_SUCCESS
操作,这将导致我们在我们的商店中获得身份验证 hash
,我们将在后续请求中使用它。
dispatch(loginSuccess(hash, data.user))
另一方面,如果出现问题,我们也想让用户知道:
dispatch(loginFailure(data.error || 'Log in failed')
loginSuccess
、loginFailure
和 loginRequest
动作创建器相当通用,并不真正保证代码示例。参见:https://github.com/peterp/redux-http-basic-auth-example/blob/master/actions/user.js)
减速机
我们的reducer也是典型的:
/// reducers/user.js
function user(state = {
isLoggingIn: false,
isAuthenticated: false
}, action) {
switch(action.type) {
case LOGIN_REQUEST:
return {
isLoggingIn: true, // Show a loading indicator.
isAuthenticated: false
}
case LOGIN_FAILURE:
return {
isLoggingIn: false,
isAuthenticated: false,
error: action.error
}
case LOGIN_SUCCESS:
return {
isLoggingIn: false,
isAuthenticated: true, // Dismiss the login view.
hash: action.hash, // Used in subsequent API requests.
user: action.user
}
default:
return state
}
}
后续 API 个请求
现在我们的商店中有一个身份验证散列,我们可以将它传递到后续请求的 headers。
在下面的示例中,我们正在为经过身份验证的用户获取好友列表:
/// actions/friends.js
export function fetchFriends() {
return (dispatch, getState) => {
dispatch(friendsRequest())
// Notice how we grab the hash from the store:
const hash = getState().user.hash
return fetch(`https://httpbin.org/get/friends/`, {
headers: {
'Authorization': `Basic ${hash}`
}
})
.then(response => response.json().then(json => ({ json, response })))
.then(({json, response}) => {
if (response.ok === false) {
return Promise.reject({response, json})
}
return json
})
.then(
data => {
// data = { friends: [ {}, {}, ... ] }
dispatch(friendsSuccess(data.friends))
},
({response, data}) => {
dispatch(friendsFailure(data.error))
// did our request fail because our auth credentials aren't working?
if (response.status == 401) {
dispatch(loginFailure(data.error))
}
}
)
}
}
您可能会发现大多数 API 请求通常会发送与上述相同的 3 个操作:API_REQUEST
、API_SUCCESS
和 API_FAILURE
,因此大多数请求/响应代码可以被推送到 Redux 中间件。
我们从商店获取哈希身份验证令牌并设置请求。
const hash = getState().user.hash
return fetch(`https://httpbin.org/get/friends/`, {
headers: {
'Authorization': `Basic ${hash}`
}
})
/* ... */
如果 API 响应带有 401 状态代码,那么我们必须从存储中删除哈希,并再次向用户显示登录视图。
if (response.status == 401) {
dispatch(loginFailure(data.error))
}
我已经笼统地回答了这个问题并且只处理 http-basic-auth。
我认为这个概念可能保持不变,你将在商店中推送 accessToken
和 refreshToken
,并在后续请求中提取它。
如果请求失败,则您必须发送另一个更新 accessToken 的操作,然后撤回原始请求。
实际上我正在制作一个视频教程系列,它至少可以回答您提出的一些问题。可以在此处找到该视频以及文字记录和示例代码:http://codecookbook.co/post/how-to-build-a-react-native-login-form-with-redux-pt1/