新的 react 和使用身份验证/登录的应用程序的工作。它目前工作但感觉一起被黑了。现在我的 isAuthenticated 状态位于我的 routes.js 中,如下所示:
class Routes extends Component {
constructor(props) {
super(props);
this.state = {
isAuthenticated: false,
}
}
在我的登录页面上,我需要知道用户何时通过身份验证才能将他们重定向到 home 页面。允许访问和操作此 isAuthenticated 状态的最佳设计模式是什么?我目前的设置方式是我有一个函数可以在 routes.js 中设置状态并将状态作为 prop 发送,如下所示:
setAuthenticated = (isAuthenticated) => {
this.setState({isAuthenticated});
}
在路由器下面...
<Route path="/" exact component={() =>
<div>
<Login
isAuthenticated={this.state.isAuthenticated}
setAuthenticated={this.setAuthenticated}
</div>
} />
是的,我知道这是一个糟糕的设计,因为这会改变本应不可变的 Prop 值。这也很糟糕,因为当我在 login.js 中更改此值时,它会导致多次不必要的重新呈现。我应该将 isAuthenticated 声明为某种类型的全局变量吗?顺便说一句,我没有使用任何状态管理。
编辑:我正在设置 isAuthenticated 基于我的服务器的响应,确认正确的登录名/密码组合。
最佳答案
处理 isAuthenticated 仅在state 表示用户每次刷新页面都将未通过身份验证。这不是真正的用户友好! :)
因此,登录页面应该存储一个access_token (来自您的后端)在 cookies 中或 localStorage 浏览器的。一个access_token证明用户已通过身份验证并验证其身份。你通常会通过这个 access_token对您的服务器的每个下一个请求,以检查该用户是否被允许访问他请求的数据,或者是否被允许创建、编辑和删除他试图创建、编辑和删除的东西。
然后你可以查看这个access_token在所有其他页面上,如果他不再通过身份验证,则将用户重定向到登录页面。
关于 access_token 之间区别的简要说明 和 refresh_token – 这将帮助您理解下面的代码,但如果您已经熟悉它,请随时跳过。
您的后端可能使用 OAuth2 ,这是当今最常见的身份验证协议(protocol)。与 OAuth2 ,您的应用向服务器发出第一个请求,其中包含用户的用户名和密码以进行身份验证。一旦用户通过身份验证,他将收到 1) access_token。 ,通常在一小时后过期,以及 2) refresh_token ,它会在很长一段时间(几小时、几天)后过期。当 access_token过期,而不是再次询问用户他的用户名和密码,你的应用程序发送 refresh_token到服务器获取新的access_token对于这个用户。
关于 cookies 之间差异的简要说明 和 localStorage – 也可以随意跳过它!
localStorage是两者之间最新的技术。这是一个简单的键/值持久化系统,似乎非常适合存储 access_token及其值(value)。但我们还需要保留其到期日期。我们可以存储名为 expires 的第二个键/值对但在我们这边处理会更合乎逻辑。
另一方面,cookies有一个本地人expires属性(property),这正是我们所需要的! cookies是一项古老的技术,对开发人员不是很友好,所以我个人使用 js-cookie ,这是一个小型图书馆来操纵cookies .它也使它看起来像一个简单的键/值持久性系统:Cookies.set('access_token', value)然后Cookies.get('access_token') .
其他亲为cookies : 他们是交叉的subdomains !如果您的登录应用程序是 login.mycompany.com并且您的主要应用程序是 app.mycompany.com , 然后你可以创建一个 cookie在登录应用程序上并从主应用程序访问它。这对于 LocalStorage 是不可能的.
以下是我用于身份验证的一些方法和特殊的 React 组件:
import Cookies from 'js-cookie'
export const getAccessToken = () => Cookies.get('access_token')
export const getRefreshToken = () => Cookies.get('refresh_token')
export const isAuthenticated = () => !!getAccessToken()
export const authenticate = async () => {
if (getRefreshToken()) {
try {
const tokens = await refreshTokens() // call an API, returns tokens
const expires = (tokens.expires_in || 60 * 60) * 1000
const inOneHour = new Date(new Date().getTime() + expires)
// you will have the exact same setters in your Login page/app too
Cookies.set('access_token', tokens.access_token, { expires: inOneHour })
Cookies.set('refresh_token', tokens.refresh_token)
return true
} catch (error) {
redirectToLogin()
return false
}
}
redirectToLogin()
return false
}
const redirectToLogin = () => {
window.location.replace(
`${getConfig().LOGIN_URL}?next=${window.location.href}`
)
// or history.push('/login') if your Login page is inside the same app
}
export const AuthenticatedRoute = ({
component: Component,
exact,
path,
}) => (
<Route
exact={exact}
path={path}
render={props =>
isAuthenticated() ? (
<Component {...props} />
) : (
<AuthenticateBeforeRender render={() => <Component {...props} />} />
)
}
/>
)
class AuthenticateBeforeRender extends Component {
state = {
isAuthenticated: false,
}
componentDidMount() {
authenticate().then(isAuthenticated => {
this.setState({ isAuthenticated })
})
}
render() {
return this.state.isAuthenticated ? this.props.render() : null
}
}
关于javascript - React - 处理登录和身份验证的最佳方式是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49819183/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..
我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput