認証/ログインを使用してアプリケーションに反応し、動作するようになりました。現在は動作していますが、一緒にハッキングされているように感じます。現在、routes.js
にあるisAuthenticated
状態は次のようになっています。
class Routes extends Component {
constructor(props) {
super(props);
this.state = {
isAuthenticated: false,
}
}
ログインページで、ユーザーがhome
ページにリダイレクトするために認証されるタイミングを知る必要があります。このisAuthenticated
状態へのアクセスと操作を可能にする最適な設計パターンは何ですか?現在どのように設定しているのかは、routes.js
内の状態を設定し、そのような状態を小道具として送信する関数があることです。
setAuthenticated = (isAuthenticated) => {
this.setState({isAuthenticated});
}
下のルーターで...
<Route path="/" exact component={() =>
<div>
<Login
isAuthenticated={this.state.isAuthenticated}
setAuthenticated={this.setAuthenticated}
</div>
} />
はい、不変であると思われる小道具の値を変更しているため、これは悪い設計であることを理解しています。 login.js
でこの値を変更すると、複数の不必要な再レンダリングが発生するため、これも悪いことです。 isAuthenticated
を何らかのグローバル変数として宣言する必要がありますか?ちなみに、私は状態管理を使用していません。
編集:正しいログイン/パスワードの組み合わせを確認するサーバーからの応答に基づいてisAuthenticated
を設定しています。
isAuthenticated
をstate
のみで処理すると、ユーザーはページを更新するたびに認証されなくなります。それは本当にユーザーフレンドリーではありません! :)
そのため、代わりに、ログインページにaccess_token
(バックエンドから来る)で cookies
または localStorage
のブラウザ。 access_token
は、ユーザーが認証されていることを証明し、ユーザーの身元も検証します。通常、これはaccess_token
サーバーへの次のすべての要求に対して、このユーザーが要求しているデータへのアクセスを許可されているか、または作成、編集、削除しようとしているものの作成、編集、削除を許可されているかを確認します。
その後、これを確認できますaccess_token
他のすべてのページでも同様であり、ユーザーがもう認証されていない場合は、ログインページにリダイレクトします。
access_token
およびrefresh_token
– 以下のコードを理解するのに役立ちますが、すでに慣れている場合はお気軽にスキップしてください。
バックエンドはおそらく OAuth2
、これは現在最も一般的な認証プロトコルです。 OAuth2
、アプリは認証するユーザーのユーザー名とパスワードを含む最初のリクエストをサーバーに送信します。ユーザーが認証されると、1)access_token
(通常は1時間後に期限切れになります)、および2)refresh_token
は、非常に長い時間(時間、日)後に期限切れになります。 access_token
が期限切れになり、ユーザーにユーザー名とパスワードを再度要求する代わりに、アプリはrefresh_token
サーバーに新しいaccess_token
このユーザー。
cookies
とlocalStorage
の違いに関する簡単な説明– feelスキップしても構いません!
localStorage
は両方の最新のテクノロジーです。これは、単純なキー/値永続化システムであり、access_token
とその値。ただし、有効期限も保持する必要があります。 expires
のような2番目のキー/値情報を保存することもできますが、処理するロジックが増えます。
一方、cookies
にはネイティブのexpires
プロパティが付属しています。これはまさに必要なものです。 cookies
は古いテクノロジーであり、開発者にとって使い勝手が悪いため、個人的に js-cookie
、これはcookies
を操作するための小さなライブラリです。
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()
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
}
}
ページ保護が「isAuthenticated」状態変数に依存している場合、おそらく react devtoolsを無効にする を本番環境で使用する必要があります。それ以外の場合、ページを検査し、フラグを手動でtrueに切り替えて、保護されたページを認証されていないユーザーに公開することができます。
ログイン時にローカルストレージにアクセストークンを設定し、ユーザーがログアウトした後にクリアすることができます。次に、認証済みメソッドを使用して、トークンがあるかどうか、およびAPI呼び出しの実行中にトークンが有効かどうかを確認します
1つのセッションの間のみ認証が続くアプリケーションを使用している場合、状態に保存するだけで十分です。ただし、これは、ユーザーがページの更新時に認証済みステータスを失うことを意味することに注意してください。
以下にReact Contextを使用した例を示します。ここでは、createContext
を使用してコンテキストを作成し、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"));
<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>