这一期主要讲解前端如何通过 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
评论