Vin*_*yen 17 javascript authentication reactjs react-router
新的用于对具有身份验证/登录的应用程序做出反应和处理.它目前有效,但感觉被黑客攻击.现在我的isAuthenticated状态routes.js就像我一样:
class Routes extends Component {
constructor(props) {
super(props);
this.state = {
isAuthenticated: false,
}
}
Run Code Online (Sandbox Code Playgroud)
在我的登录页面上,我需要知道用户何时通过身份验证才能将其重定向到home页面.允许访问和操纵此isAuthenticated状态的最佳设计模式是什么?我目前如何设置它是我有一个功能,设置内部的状态routes.js,并将状态作为道具发送,如下所示:
setAuthenticated = (isAuthenticated) => {
this.setState({isAuthenticated});
}
Run Code Online (Sandbox Code Playgroud)
在路由器下面......
<Route path="/" exact component={() =>
<div>
<Login
isAuthenticated={this.state.isAuthenticated}
setAuthenticated={this.setAuthenticated}
</div>
} />
Run Code Online (Sandbox Code Playgroud)
是的,我理解这是糟糕的设计,因为这是改变道具值,这些道具值应该是不可变的.这也很糟糕,因为当我更改此值时login.js会导致多次不必要的重新渲染.我应该宣布isAuthenticated某种类型的全局变量吗?顺便说一下,我没有使用任何国家管理.
编辑:我isAuthenticated根据服务器的响应进行设置,确认正确的登录/密码组合.
GG.*_*GG. 39
isAuthenticated 仅以这种state方式处理意味着用户在每次刷新页面时都将不经过身份验证。那不是真正的用户友好!:)
因此,登录页面应该在浏览器的或中存储access_token(来自您的后端)。可以证明用户已通过身份验证,也可以验证其身份。通常,您通常会将其传递给服务器的下一个请求,以检查是否允许该用户访问他所请求的数据,或者是否允许该用户创建,编辑和删除他尝试创建,编辑和删除的内容。cookieslocalStorageaccess_tokenaccess_token
然后,您也可以access_token在其他所有页面上进行检查,如果用户不再通过身份验证,则将其重定向到“登录”页面。
除了access_token和refresh_token– 之间的区别之外,还简要介绍一下这将有助于您理解下面的代码,但是如果您已经熟悉它,可以随时跳过。
您的后端可能使用OAuth2,这是当今最常见的身份验证协议。使用OAuth2,您的应用会向服务器发出第一个请求,其中包含要进行身份验证的用户名和密码。用户通过身份验证后,他会收到1)和access_token(通常会在一个小时后过期)和2)a refresh_token(会在很长的时间(小时,天)之后过期)。当access_token过期的,而不是再次要求他的用户名和密码的用户,您的应用程序发送refresh_token到服务器,以获得新的access_token这个用户。
除了cookies和之间的区别之外,还简要介绍一下localStorage-也可以跳过它!
localStorage是两者之间的最新技术。这是一个简单的键/值持久性系统,似乎非常适合存储access_token和其值。但我们还需要保留其到期日期。我们可以存储第二个名为的键/值对,expires但这将是逻辑上更多的事情。
另一方面,cookies拥有本机expires属性,这正是我们所需要的!cookies是一项过时的技术,并且对开发人员不太友好,因此我个人使用js-cookie这是一个小型库来进行操作cookies。它也使它看起来像一个简单的键/值持久性系统:Cookies.set('access_token', value)then Cookies.get('access_token')。
其他支持cookies:它们是跨子域!如果您的登录应用程序是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()
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)
export const AuthenticatedRoute = ({
component: Component,
exact,
path,
}) => (
<Route
exact={exact}
path={path}
render={props =>
isAuthenticated() ? (
<Component {...props} />
) : (
<AuthenticateBeforeRender render={() => <Component {...props} />} />
)
}
/>
)
Run Code Online (Sandbox Code Playgroud)
class AuthenticateBeforeRender extends Component {
state = {
isAuthenticated: false,
}
componentDidMount() {
authenticate().then(isAuthenticated => {
this.setState({ isAuthenticated })
})
}
render() {
return this.state.isAuthenticated ? this.props.render() : null
}
}
Run Code Online (Sandbox Code Playgroud)
如果您使用的应用程序的身份验证仅持续一个会话,则将其存储在状态中就足够了。但请注意,这意味着用户将在页面刷新时失去已验证状态。
这是一个使用 React Context 的示例,我们在其中创建上下文 usingcreateContext并用于Consumer跨应用程序访问它。
const AuthenticationContext = React.createContext();
const { Provider, Consumer } = AuthenticationContext;
function Login(props) {
return (
<Consumer>
{
value=>
<button onClick={value.login}>Login</button>
}
</Consumer>
);
}
function Logout() {
return (
<Consumer>
{
value=>
<button onClick={value.logout}>Logout</button>
}
</Consumer>
);
}
function AnotherComponent() {
return (
<Consumer>
{
value=>{
return value.isAuthenticated?
<p>Logged in</p>:
<p>Not Logged in</p>
}
}
</Consumer>
);
}
class App extends React.Component {
constructor(props) {
super(props);
this.login = ()=> {
this.setState({
isAuthenticated: true
});
}
this.logout = ()=> {
this.setState({
isAuthenticated: false
});
}
this.state = {
isAuthenticated: false,
login: this.login,
logout: this.logout
}
}
render() {
return (
<Provider value={this.state}>
<Login />
<Logout />
<AnotherComponent />
</Provider>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));Run Code Online (Sandbox Code Playgroud)
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div> Run Code Online (Sandbox Code Playgroud)
https://reactjs.org/docs/context.html#reactcreatecontext
小智 5
如果页面保护依赖于“ isAuthenticated”状态变量,则可能应该在生产环境中禁用react devtools。否则,可以检查页面并手动将标志翻转为true,从而将受保护的页面暴露给未经身份验证的用户。
| 归档时间: |
|
| 查看次数: |
17829 次 |
| 最近记录: |