ant design pro +react+identityServer4 部署教程

新公司需要用到 identityServer4 来做微服务的架构部署。其中一个项目使用前端 ant design pro +react 后端使用 .net core,关于identityServer4 的部署和identityServer4与后端的整合这里就不讲了,网上很多类似的讲解,这里只讲ant design pro +react与identityServer4 的集成,网上也有很多其他前端与identityServer4 的集成,都是现成的拿下来跑,没有怎么详细的讲解,与ant design pro +react也有一些差异。

1、首先把identityServer4  部署好,这里有一个现成的,大家可以直接下载下来运行就行:https://github.com/skoruba/IdentityServer4.Admin,建议把https改成http。其他详细步骤就不讲了。

2、在官网下载 ant design pro +react:https://pro.ant.design

直接下载,然后安装相关依赖(安装依赖步骤就不讲了)。

antd 的语言版本,TypeScript 或 JavaScript,我这里选的是JavaScript,根据个人需要选择。

3、ant design pro +react想和 identityServer4 需要借助的三方插件oidc-client,所以我们也需要安装oidc-client依赖,安装完成之后在src/services 下新建两个文件

,里面的代码我就直接copy下来了

ApiServerce.js:

/* eslint-disable */
import axios from 'axios'
import Mgr from './SecurityService'
import 'babel-polyfill';

const baseUrl = 'https://localhost:44390/api/';
var user = new Mgr()

 export async function defineHeaderAxios () {
    await user.getAcessToken().then(
      acessToken => {
        axios.defaults.headers.common['Authorization'] = 'Bearer ' + acessToken
      }, err => {
        console.log(err)
      })  
  }
  export async function  getAll(api){
    await this.defineHeaderAxios() 
    return axios
      .get(baseUrl + api)
      .then(response => response.data)
      .catch(err => {
        console.log(err);
      })
  }


 SecurityService.js:

/* eslint-disable */
import Oidc from 'oidc-client';
import 'babel-polyfill';

var mgr = new Oidc.UserManager({
  userStore: new Oidc.WebStorageStateStore(),  
  //authority: 'http://it-dev-win.incubecn.com:44310',
  authority: 'http://localhost:44310',
  client_id: 'reackjsclient',
  redirect_uri: window.location.origin + '/callback.html',
  // redirect_uri: window.location.origin + '/page/user/login/index.jsx',
  response_type: 'code',
  scope: 'openid profile email roles',
  post_logout_redirect_uri: window.location.origin + '/index.html',
  silent_redirect_uri: window.location.origin + '/silent-renew.html',
  accessTokenExpiringNotificationTime: 10,
  automaticSilentRenew: true,
  filterProtocolClaims: true,
  loadUserInfo: true
})

Oidc.Log.logger = console;
Oidc.Log.level = Oidc.Log.INFO;

mgr.events.addUserLoaded(function (user) {  
  console.log('New User Loaded:', arguments);
  console.log('Acess_token: ', user.access_token)
});

mgr.events.addAccessTokenExpiring(function () {
  console.log('AccessToken Expiring:', arguments);
});

mgr.events.addAccessTokenExpired(function () {
  console.log('AccessToken Expired:', arguments);  
  alert('Session expired. Going out!');
  mgr.signoutRedirect().then(function (resp) {
    console.log('signed out', resp);
  }).catch(function (err) {
    console.log(err)
  })
});

mgr.events.addSilentRenewError(function () {
  console.error('Silent Renew Error:', arguments);
});

// mgr.events.addUserSignedOut(function () {
//   alert('Going out!');
//   console.log('UserSignedOut:', arguments);  
//   mgr.signoutRedirect().then(function (resp) {
//     console.log('signed out', resp);
//   }).catch(function (err) {
//     console.log(err)
//   })
// });

export default class SecurityService {

  // Renew the token manually
  renewToken () {
    let self = this
    return new Promise((resolve, reject) => {
      mgr.signinSilent().then(function (user) {
        if (user == null) {
          self.signIn(null)
        } else{
          return resolve(user)
        }
      }).catch(function (err) {
        console.log(err)
        return reject(err)
      });
    })
  }

  // Get the user who is logged in
  getUser () {
    let self = this
    return new Promise((resolve, reject) => {
      mgr.getUser().then(function (user) {
        if (user == null) {
          self.signIn()
          return resolve(null)
        } else{          
          return resolve(user)
        }
      }).catch(function (err) {
        console.log(err)
        return reject(err)
      });
    })
  }

  // Check if there is any user logged in
  getSignedIn () {
    let self = this
    return new Promise((resolve, reject) => {
      mgr.getUser().then(function (user) {
        if (user == null) {
          self.signIn()
          return resolve(false)
        } else{
          return resolve(true)
        }
      }).catch(function (err) {
        console.log(err)
        return reject(err)
      });
    })
  }

  // Redirect of the current window to the authorization endpoint.
  signIn () {
    mgr.signinRedirect().catch(function (err) {
      console.log(err)
    })
  }
  
  // Redirect of the current window to the end session endpoint
  signOut () {    
    mgr.signoutRedirect().then(function (resp) {
      console.log('signed out', resp);
    }).catch(function (err) {
      console.log(err)
    })
  }

  // Get the profile of the user logged in
  getProfile () {
    let self = this
    return new Promise((resolve, reject) => {
      mgr.getUser().then(function (user) {
        if (user == null) {
          self.signIn()
          return resolve(null)
        } else{          
          return resolve(user.profile)
        }
      }).catch(function (err) {
        console.log(err)
        return reject(err)
      });
    })
  }

  // Get the token id
  getIdToken(){
    let self = this
    return new Promise((resolve, reject) => {
      mgr.getUser().then(function (user) {
        if (user == null) {
          self.signIn()
          return resolve(null)
        } else{          
          return resolve(user.id_token)
        }
      }).catch(function (err) {
        console.log(err)
        return reject(err)
      });
    })
  }

  // Get the session state
  getSessionState(){
    let self = this
    return new Promise((resolve, reject) => {
      mgr.getUser().then(function (user) {
        if (user == null) {
          self.signIn()
          return resolve(null)
        } else{          
          return resolve(user.session_state)
        }
      }).catch(function (err) {
        console.log(err)
        return reject(err)
      });
    })
  }

  // Get the access token of the logged in user
  getAcessToken(){
    let self = this
    return new Promise((resolve, reject) => {
      mgr.getUser().then(function (user) {
        if (user == null) {
          self.signIn()
          return resolve(null)
        } else{          
          return resolve(user.access_token)
        }
      }).catch(function (err) {
        console.log(err)
        return reject(err)
      });
    })
  }

  // Takes the scopes of the logged in user
  getScopes(){
    let self = this
    return new Promise((resolve, reject) => {
      mgr.getUser().then(function (user) {
        if (user == null) {
          self.signIn()
          return resolve(null)
        } else{          
          return resolve(user.scopes)
        }
      }).catch(function (err) {
        console.log(err)
        return reject(err)
      });
    })
  }

  // Get the user roles logged in
  getRole () {
    let self = this
    return new Promise((resolve, reject) => {
      mgr.getUser().then(function (user) {
        if (user == null) {
          self.signIn()
          return resolve(null)
        } else{          
          return resolve(user.profile.role)
        }
      }).catch(function (err) {
        console.log(err)
        return reject(err)
      });
    })
  }
}

在public 文件下面新增这里几个文件,是oidc-client需要用到的

callback.html:

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>Waiting...</title>
</head>

<body>
  <h1>Authentification callback processing...</h1>
  <script src="oidc-client.js"></script>
  <script>

    var mgr = new Oidc.UserManager({userStore: new Oidc.WebStorageStateStore(), loadUserInfo: true, filterProtocolClaims: true});
    
    mgr.signinRedirectCallback().then(function (user) {
      window.location.href = '../';
    }).catch(function (err) {
      console.log(err);
    });

  </script>
</body>

</html>

silent-renew.html:

<!DOCTYPE html>
<html>
<head>
    <title>Silent Renew Token for SpeEDI Cargo</title>
</head>
<body>
    <script src='oidc-client.js'></script>
    <script>        
        console.log('trying to renew the acess_token')
        new Oidc.UserManager().signinSilentCallback();
    </script>
</body>
</html>

oidc-client.js和oidc-client.min.js直接去百度下载就行了。

 从上面直到这里,网上去找一些教程大部分都是有的,下面这些就是自己一点点摸索出来的。

一、配置identityServer4

1.打开后台管理界面

2.点击客户端管理

这里是我新建过的,你们开始的话直接添加客户端就行了 

3.客户端标识

 客户端标识是要和前端配置一致的,不然访问的时候会提示没有授权,在前端SecurityService.js文件里面:client_id: 'reackjsclient',(上面代码有)

4.基本

 

其他配置默认一致就行了,主要是这个重定向Uri,这个Uri需要配置和 SecurityService.js文件里面redirect_uri参数一致(redirect_uri: window.location.origin + '/callback.html',),10.18.11.81是我本地IP,8000是前端启动的端口,这里还需要保证这里路劲能正常访问。

5.认证\注销

 1.前端通道注销 Uri 照着填就行了,把地址和端口改成你自己前端的,这里他是调用第三方插件(oidc-client)的注销地址,

2.注销重定向 Uri:这玩意也是照着填就行了,把地址和端口改成你自己前端的,这个目前没看着有啥用,意思就是注销之后跳转的界面(不知道对不对,这个不是特别重要,后面如果有大佬知道是什么麻烦告诉我一下,谢谢)。

6.令牌

 

 其他选项默认成一样的就行了,这里只有一个允许跨域来源需要注意一下,前端访问IdentityServer4是会跨域的,我们也不需要使用其他的工具来解决跨域问题,直接在这里配置一下前端的端口就行了(本地IP+端口)。

7.同意屏幕

 客户端Uri改成你自己的ip+端口

至此,identityServer4配置基本上配置好了,如果访问过程中,有提示没有授权或者无效的请求就检查前端配置的路劲和identityServer4配置的路劲是否一致。

网上其他一些现成的demo基本上最多就是这么多了,但是官方的ant design pro和网上大部分demo都不一样,所以后续还有很多需要处理的地方。

Ant Design Pro前端配置

1.首先你运行前端需要到id(identityServer4,后面都用id4简称标识)上做登录和权限认证,我这里的做法是运行前端登录界面时直接跳转过去,你也可以设置一个按钮点击跳转,看个人需求

 

跳转方法是第三方插件oidc-client写好了的,直接调用就行。

2.当你到Id4里面登陆之后,登录信息是存在第三方插件里面的,如role,token,name等,后面都会用到这些信息。

这时候可能发生一种情况,你登录之后跳转到callback.html界面之后又跳转回登录界面,这是因为ant design pro 官方代码里面写了一些逻辑(其他网上demo里面没有这写逻辑的),这对于从来没接触过ant design pro+reack的人来说不太友好。

在APP.JSX里面 将fetchUserInfo方法里面的代码改成下面这样:

  const fetchUserInfo = async () => {
    try {
       const Mgrs = new Mgr()
       const currentUser=await Mgrs.getUser();
      return currentUser;
    } catch (error) {
      history.push(loginPath);
    }
    return undefined;
  }; //

这里的意思是从第三方插件里面去获取用户信息包括token等信息,token这些是访问后端API做权限管控需要的,原来这里的代码是向一个后端API里面拿员工信息,因为我们没有部署后端API并且我们是在id4里面登录的,所以原来代码在这里根本拿不到登录信息,当拿不到登录信息时,就会跳转到登录界面,所以就会出现在id4登录之后又重新跳转到前端登录界面的情况。

当这里代码处理好之后就可以正常登录了。

2.登出,登出比登录简单多了,只要调用第三方插件的登出方法就行了,这里就不多讲了。

至此,ant design pro +react+identityServer4的部署集成就完成了,回头来看其实并不难,只是两者都是刚刚接触,不了解其中运行原理,当出现错误时会一头蒙。

主要有两点:

一:id4与前端的配置需要一致

二:前端登录之后的跳转。(获取到role和token等信息)

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值