这一期主要讲解前端如何通过 BFF 层来使用自己的认证中心。
首先说明什么是 BFF 层,BFF 是 Backend For Frontend 的缩写,它主要有几个作用。
1、它可以是有状态的,可以通过 cookie 跟前端交互。
2、可以避免密码信息直接暴露到前端页面。
3、保护后端服务,前端都是暴露到公网的,它对应访问的 api 都是需要公网可以访问的,如果是直接访问后端服务的话,那就需要后端服务暴露到公网,如果有 BFF 这一层,我们只需要暴露 BFF 层到公网,然后在 BFF 层做一个代理到后端的服务。
搭建 BFF 层
BFF 层是一个很轻量的应用,你也可以使用 nodejs 或者其他任何语言来实现,我这里使用的是 golang,这里不会涉及到代理,只涉及如何跟认证中心交互。
1、配置认证中心的信息,这里就会有 clientId 和 clientsecret 的信息。
var (
AppUrl = "http://localhost:5173/"
MyAuthUrl = "http://localhost:8000/oauth2/token?grant_type=authorization_code&code=%s&redirect_uri=%s"
RefreshToken = "http://localhost:8000/oauth2/token?grant_type=refresh_token&refresh_token=%s"
BFFClientId = "bff"
BFFClientSecret = "bff"
)
复制代码
2、通过 code 获取 refresh token 和 access token,调用认证中心的 api 的时候需要传入你的 clientId 和 clientSecret,这里可以多做一步就是在服务端缓存 tokens,避免发送重复请求到认证中心,下面是一个通过 code 来获取 refreshtoken 和 accesstoken 的示例。
func RequestToken(c echo.Context) error {
code := c.QueryParams().Get("code")
authUrl := fmt.Sprintf(MyAuthUrl, code, AppUrl)
req, err := http.NewRequest("POST", authUrl, nil)
if err != nil {
panic(err)
}
req.SetBasicAuth(BFFClientId, BFFClientSecret)
client := http.DefaultClient
response, err := client.Do(req)
if err != nil {
panic(err)
}
return c.JSON(http.StatusOK, HandleResponse(response))
}
复制代码
3、解析返回的 response 给到前端使用。
func HandleResponse(response *http.Response) map[string]any {
defer response.Body.Close()
b, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
var x = map[string]any{}
json.Unmarshal(b, &x)
return x
}
复制代码
前端使用
1、前端判断 localstorage 是否有 refreshtoken,如果没有或者失效,跳转到登录页面重新获取 code 来生成 token。
2、前端拿到 token 后存入到 localstorage。
async function tokens() {
const { data } = await fetchTokens(code.value)
if (data) {
console.info(data)
if (data.error !== undefined) {
return true
} else {
window.localStorage.setItem("refresh_token", data.refresh_token)
window.localStorage.setItem("access_token", data.access_token)
window.localStorage.setItem("scope", data.scope)
return false
}
}
}
复制代码
3、使用 accesstoken 去获取资源服务器的资源。
export async function userName() {
let accessToken = window.localStorage.getItem("access_token")
return await axios.get("http://localhost:8001/greet2", {
headers: {
Authorization: "Bearer " + accessToken
}
}).then(async response => {
return response
}).catch(response => {
console.info(response)
return response
})
}
复制代码
这样整一个流程就完成了,你可以在前端定制化 axios 添加 interceptor 来避免每次都要添加一个 Authorization 的 header。
大家可以动手试试,有问题可以评论区留言。
视频地址:如何搭建一个专属的认证中心(四)完结篇_哔哩哔哩_bilibili
评论