{"id":304884,"date":"2020-06-05T09:01:29","date_gmt":"2020-06-05T09:01:29","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=304884"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=304884","title":{"rendered":"\u0421\u043a\u0430\u0437 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u044f \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u043b Azure AD B2C \u043d\u0430 React \u0438 React Native \u0427\u0430\u0441\u0442\u044c 4 (\u0422\u0443\u0442\u043e\u0440\u0438\u0430\u043b)"},"content":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/505408\/\">\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/hd\/t3\/3_\/hdt33_njadqtiqzzjijasdxhzfy.png\" alt=\"image\"><\/div>\n<p>  <\/p>\n<h3>\u041f\u0440\u0435\u0434\u0438\u0441\u043b\u043e\u0432\u0438\u0435<\/h3>\n<p>  \u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u0446\u0438\u043a\u043b\u0430 \u043f\u043e \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 Azure B2C. \u0412 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e \u043d\u0430 React Native.<\/p>\n<p>  <b>\u0421\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u0441\u0442\u044b<\/b><\/p>\n<ul>\n<li><a href=\"https:\/\/habr.com\/ru\/post\/503890\/\">\u0427\u0430\u0441\u0442\u044c 1: \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043d\u0430 Azure AD B2C<\/a><\/li>\n<li><a href=\"https:\/\/habr.com\/ru\/post\/504030\/\">\u0427\u0430\u0441\u0442\u044c 2: \u0420\u0430\u0431\u043e\u0442\u0430 \u0441 Identity Framework Experience<\/a><\/li>\n<li><a href=\"https:\/\/habr.com\/ru\/post\/504690\/\">\u0427\u0430\u0441\u0442\u044c 3: \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f React<\/a><\/li>\n<li>\u0427\u0430\u0441\u0442\u044c 4: \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f React Native<\/li>\n<li>\u0427\u0430\u0441\u0442\u044c 5: \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0431\u044d\u043a\u044d\u043d\u0434\u0430 \u043d\u0430 .NET Core 3<\/li>\n<\/ul>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<h2><font color=\"#D03C31\">\u0428\u0410\u0413 1<\/font><\/h2>\n<p>  \u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c <a href=\"https:\/\/www.npmjs.com\/package\/react-native-app-auth\" rel=\"nofollow\">react-native-app-auth<\/a> <b>(npm i react-native-app-auth)<\/b>.<\/p>\n<h2><font color=\"#D03C31\">\u0428\u0410\u0413 2<\/font><\/h2>\n<p>  \u041e\u0442\u043a\u0440\u044b\u0442\u044c \u0432 Azure AD B2C \u0432\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u0412\u043e \u0432\u043a\u043b\u0430\u0434\u043a\u0435 <b>\u00ab\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u043e\u0434\u043b\u0438\u043d\u043d\u043e\u0441\u0442\u0438\u00bb<\/b> \u2014 \u043d\u0430\u0436\u0430\u0442\u044c <b>\u00ab\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0443\u00bb<\/b>.<br \/>  \u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u0431\u0440\u0430\u0442\u044c <b>Android<\/b> \u0438 <b>iOS<\/b>.<br \/>  <a href=\"https:\/\/habrastorage.org\/webt\/pv\/uy\/zf\/pvuyzf7p-aagmalxcsgzrcpmmz8.png\" rel=\"nofollow\"> <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/pv\/uy\/zf\/pvuyzf7p-aagmalxcsgzrcpmmz8.png\"><\/a><\/p>\n<p>  \u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u0432\u044b \u0441\u043e\u0437\u0434\u0430\u0442\u0438\u0435 \u043e\u0431\u0435 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0432\u044b \u043f\u043e\u043b\u0447\u0438\u0442\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435:<br \/>  <a href=\"https:\/\/habrastorage.org\/webt\/gv\/bm\/vm\/gvbmvmu6b_gbjzktbg0ykaq-1_4.png\" rel=\"nofollow\"> <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/gv\/bm\/vm\/gvbmvmu6b_gbjzktbg0ykaq-1_4.png\"><\/a><\/p>\n<h2><font color=\"#D03C31\">\u0428\u0410\u0413 3<\/font><\/h2>\n<p>  \u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0444\u0430\u0439\u043b <b>auth-provider.js<\/b> \u0432 \u043f\u0430\u043f\u043a\u0435 <b>.\/src<\/b>  <\/p>\n<pre><code class=\"javascript\">  import { authorize, revoke, refresh } from 'react-native-app-auth';   const config = (page) =&gt; ({     \/\/ \u041d\u0430\u0439\u0442\u0438 issuer \u043c\u043e\u0436\u043d\u043e \u0432\u043e \u0432\u043a\u043b\u0430\u0434\u043a\u0435 &quot;\u041e\u0431\u0437\u043e\u0440&quot;. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 &quot;\u041a\u043e\u043d\u0435\u0447\u043d\u044b\u0435 \u0442\u043e\u0447\u043a\u0438&quot;.     \/\/ \u0422\u0430\u043a\u0436\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c &quot;tfp&quot; \u043a\u0430\u043a \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e \u0432 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043d\u0438\u0436\u0435.      \/\/ \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u043d\u0443\u0436\u043d\u0443\u044e \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0443.     issuer: `https:\/\/myapp.b2clogin.com\/tfp\/mycompany.onmicrosoft.com\/${pages[page]}`,     \/\/ ClientID \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f Azure AD B2C     clientId: '777aaa77a-7a77-7777-bb77-8888888aabc',     scopes: ['openid'], \/\/ \u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043a\u0430\u0436\u0438\u0442\u0435 openid     \/\/ \u041d\u0443\u0436\u043d\u043e \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0439 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043c\u043e\u0433      \/\/ \u0441\u043d\u043e\u0432\u0430 \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0441\u043f\u043e\u0441\u043e\u0431 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 (Google, Facebook \u0438 \u0442.\u0434.)     additionalParameters: { prompt: 'login' },     \/\/ URI \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f (Android)     redirectUrl: 'msauth:\/\/com.myapp\/asdasd%o293o4iro21342\/',   });   const logOutConfig = {     clientId: '777aaa77a-7a77-7777-bb77-8888888aabc',     serviceConfiguration: {       revocationEndpoint:         'https:\/\/mycompany.b2clogin.com\/mycompany.onmicrosoft.com\/B2C_1A_SignIn\/oauth2\/v2.0\/logout',     },   };   \/\/ \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0443 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f   const pages = {     signIn: 'B2C_1A_SignIn',     signUp: 'B2C_1A_SignUp',     resetPassword: 'B2C_1A_PasswordReset',   };    \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 Azure.   const getAzureData = async (page) =&gt; {     try {       const data = await authorize(config(page));       return data;     } catch (e) {       requestErrorHandler(e, 'azure authorize error');     }   };    export const signIn = () =&gt; async (dispatch) =&gt; {     const authMethod = 'signIn';     try {       const data = await getAzureData(authMethod);       dispatch(userRegistration(data, authMethod));     } catch (e) {       requestErrorHandler(e, 'sign in error');     }   };     export const azureLogOut = () =&gt; async (dispatch, getState) =&gt; {     const { refreshToken } = getState().Authentication;     try {       await revoke(logOutConfig, {         tokenToRevoke: refreshToken,         sendClientId: true,       });       dispatch(authActions.logOut());     } catch (e) {       console.warn(e);     }   }; <\/code><\/pre>\n<p>  <b>\u0413\u0434\u0435 \u0431\u0440\u0430\u0442\u044c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u043f\u043e\u043b\u0438\u0442\u0438\u043a \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u043d\u0430 \u0441\u043a\u0440\u0438\u043d\u0448\u043e\u0442\u0435<\/b><br \/>  <a href=\"https:\/\/habrastorage.org\/webt\/-d\/bv\/nb\/-dbvnbzig1vatibisepcb9ekdxq.png\" rel=\"nofollow\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/-d\/bv\/nb\/-dbvnbzig1vatibisepcb9ekdxq.png\" alt=\"image\"><\/a><\/p>\n<h2><font color=\"#D03C31\">\u0428\u0410\u0413 4<\/font><\/h2>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0443\u0436\u043d\u043e \u0432\u043d\u0435\u0441\u0442\u0438 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0444\u0430\u0439\u043b\u044b:<\/p>\n<p>  <b>\/android\/app\/build.gradle<\/b>  <\/p>\n<pre><code class=\"xml\">  defaultConfig {     manifestPlaceholders = [         appAuthRedirectScheme: 'msauth'     ]      ...   } <\/code><\/pre>\n<p>  <b>\/ios\/yourApp\/Info.plist<\/b>  <\/p>\n<pre><code class=\"xml\">&lt;key&gt;CFBundleURLTypes&lt;\/key&gt; &lt;array&gt; ...     &lt;dict&gt;     &lt;key&gt;CFBundleURLName&lt;\/key&gt;     &lt;string&gt;com.yourApp&lt;\/string&gt;     &lt;key&gt;CFBundleURLSchemes&lt;\/key&gt;     &lt;array&gt;       &lt;string&gt;msauth.com.yourApp&lt;\/string&gt;     &lt;\/array&gt;   &lt;\/dict&gt; &lt;\/array&gt; <\/code><\/pre>\n<p>  <\/p>\n<h2><font color=\"#D03C31\">\u0428\u0410\u0413 5<\/font><\/h2>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0442\u043e\u043a\u0435\u043d, \u0447\u0442\u043e \u0431\u044b \u043d\u0435 \u043f\u0440\u043e\u0441\u0438\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043a\u043e\u0433\u0434\u0430 \u043e\u043d \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u0432\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043a\u0430\u0447\u0430\u0442\u044c <b><a href=\"https:\/\/www.npmjs.com\/package\/redux-persist-sensitive-storage\" rel=\"nofollow\">redux-persist-sensitive-storage<\/a><\/b> <br \/>  (npm i redux-persist-sensitive-storage).  <\/p>\n<blockquote>\n<pre><code class=\"plaintext\">    import { compose, applyMiddleware, createStore } from &quot;redux&quot;;     import { persistStore, persistCombineReducers } from &quot;redux-persist&quot;;     import createSensitiveStorage from &quot;redux-persist-sensitive-storage&quot;;     import reducers from &quot;.\/reducers&quot;; \/\/ where reducers is an object of reducers      const storage = createSensitiveStorage({       keychainService: &quot;myKeychain&quot;,       sharedPreferencesName: &quot;mySharedPrefs&quot;     });      const config = {       key: &quot;root&quot;,       storage,     };      const reducer = persistCombineReducers(config, reducers);      function configureStore () {       \/\/ ...       let store = createStore(reducer);       let persistor = persistStore(store);        return { persistor, store };     }   <\/code><\/pre>\n<p>  <\/p><\/blockquote>\n<p>  <\/p>\n<h2><font color=\"#D03C31\">\u0428\u0410\u0413 6<\/font><\/h2>\n<p>  \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0442\u043e\u043a\u0435\u043d\u0430  <\/p>\n<pre><code class=\"javascript\">  export const autoSignIn = (params) =&gt; async (dispatch) =&gt; {     try {       const userData = await getRefreshedAzureUserData(params);       await dispatch(openApplication(userData, params.authMethod));     } catch (e) {       requestErrorHandler(e, 'auto sign in error');     }   };   export const getRefreshedAzureUserData = async ({ refreshToken, authMethod }) =&gt; {     try {       const result = await refresh(config(authMethod), { refreshToken });       return result;     } catch (e) {       requestErrorHandler(e, 'get refresh token error');     }   }; <\/code><\/pre>\n<h3>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h3>\n<p>  \u0412\u0443\u0430\u043b\u044f. \u0432\u0441\u0435 \u0433\u043e\u0442\u043e\u0432\u043e! \u0422\u0435\u043f\u0435\u0440\u044c \u0432\u0430\u0448\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0441\u043c\u043e\u0433\u0443\u0442 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u0432\u0430\u0448\u0435\u043c \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438.<\/p>\n<p>  \u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435!<\/p><\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/505408\/\"> https:\/\/habr.com\/ru\/post\/505408\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/505408\/\">\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/hd\/t3\/3_\/hdt33_njadqtiqzzjijasdxhzfy.png\" alt=\"image\"><\/div>\n<p>  <\/p>\n<h3>\u041f\u0440\u0435\u0434\u0438\u0441\u043b\u043e\u0432\u0438\u0435<\/h3>\n<p>  \u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u0446\u0438\u043a\u043b\u0430 \u043f\u043e \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 Azure B2C. \u0412 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e \u043d\u0430 React Native.<\/p>\n<p>  <b>\u0421\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u0441\u0442\u044b<\/b><\/p>\n<ul>\n<li><a href=\"https:\/\/habr.com\/ru\/post\/503890\/\">\u0427\u0430\u0441\u0442\u044c 1: \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043d\u0430 Azure AD B2C<\/a><\/li>\n<li><a href=\"https:\/\/habr.com\/ru\/post\/504030\/\">\u0427\u0430\u0441\u0442\u044c 2: \u0420\u0430\u0431\u043e\u0442\u0430 \u0441 Identity Framework Experience<\/a><\/li>\n<li><a href=\"https:\/\/habr.com\/ru\/post\/504690\/\">\u0427\u0430\u0441\u0442\u044c 3: \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f React<\/a><\/li>\n<li>\u0427\u0430\u0441\u0442\u044c 4: \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f React Native<\/li>\n<li>\u0427\u0430\u0441\u0442\u044c 5: \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0431\u044d\u043a\u044d\u043d\u0434\u0430 \u043d\u0430 .NET Core 3<\/li>\n<\/ul>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-304884","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/304884","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=304884"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/304884\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=304884"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=304884"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=304884"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}