企业级单点登录实现方案OAuth2——前端登录及请求实现参考

企业级单点登录实现方案OAuth2——前端登录及请求实现参考

当后端使用Spring Security Oauth2的方式控制权限时,密码模式下前端有两个地方的实现需要关注,一是登录;二是登录后的其它接口调用。

本示例为Vue实现,使用axios来进行接口调用。

1. 登录

登录需要需要调用/oauth/token接口,并传入相关登录信息,代码实现如下:

// 组装登录参数
let params = {
    username: this.userLoginForm.username,
    password: this.passwordEncode(this.userLoginForm.password),
    id: "testResource",
    client_id: "test",
    client_secret: "secret",
    scope: "read",
    grant_type: "password",
    type: "user",
};
// 发起请求
this.$postUrlParams("/oauth/token", params)
    .then((res) => {
        this.loading = false;
        this.$cacheToken(res.access_token);
        // 登录成功后获取用户信息
        ...
    })
    .catch(() => {
        this.loading = false;
    });

注意

1. 登录成功后,我们需要将返回的token存储起来,以便在后续请求中使用这个Token。(如何使用后文会说明,可以将这个token存储到localStorage中)

2. 相关参数一定要与后端资源服务器中配置的信息匹配,否则会登录失败;

3. 客户端模式与上述过程类似,但传的参数不一样,不需要用户名及密码;

其中postUrlPrarams方法定义如下:

const myAxios = axios.create({
        baseURL: "/api/front",
        timeout: 20000,
        headers: {
            post: {
                "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
            },
        },
    });
function postUrlParams(url, param) {
        return new Promise((resolve, reject) => {
            myAxios
                .post(url, param)
                .then(
                    (response) => {
                        resolve(response);
                    },
                    (err) => {
                        if (err.status === 404) {
                            Message.error("系统异常(404)");
                        } else {
                            reject(err);
                        }
                    }
                )
                .catch((error) => {
                    console.log(error);
                    reject(error);
                });
        });
    }

实现后登录接口请求内容如下所示:

单点登录原理_默认市值单偏离点差是什么意思_单相变三相原理模电

登录请求内容

注意content-type需要是指定类型的;请求的数据需要是“表单数据”这种格式,其它格式都会报错。

2. 登录后接口调用

登录后调用后端接口时,需要在请求头中添加Authentication项,设置其值为bearer + 空格 + 登录返回的token;使用axios时,可以通过interceptor来统一处理:

const myAxios = axios.create({
        baseURL: "/api/front",  
        timeout: 20000,
        headers: {
            post: {
                "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
            },
        },
    });
    //POST传参序列化(添加请求拦截器)
    myAxios.interceptors.request.use(
        (config) => {
            if (config.method === "post") {
                let contentType = config.headers["Content-Type"];
                if (contentType !== "application/json;charset=UTF-8" && contentType !== "multipart/form-data") {
                    config.data = qs.stringify(config.data);
                }
            }
            let token = window.localStorage.getItem("ttAccessToken");
            // 登录请求中不能包含有token,否则会有报异常
            // 其它请求将token带上
            if (token && config.url.indexOf("/oauth/token") === -1) {
                config.withCredentials = true;
                config.headers.Authorization = "Bearer " + token;
            }
            return config;
        },
        (error) => {
            console.log("错误的传参");
            return Promise.reject(error);
        }
    );

同时建议处理当后端返回401、402等情况时,重新跳转到登录页面,如:

    //返回状态判断(添加响应拦截器)
    myAxios.interceptors.response.use(
        (res) => {
            if (res.data.code == "200") {
                return Promise.resolve(res.data.data);
            } else if (res.data.access_token) {
                return Promise.resolve(res.data);
            }
            console.log(res.data);
            Message.error(res.data.msg || "系统异常");
            return Promise.reject(res.data);
        },
        (error) => {
            console.log(error);
            let resp = error.response;
            let status = resp.status;
            if (status === 401 || status === 402) {
                window.localStorage.removeItem("ttAccessToken");
                store.commit("needLogin");
            } else if (status === 500 && !resp.data.error_description) {
                // 如果后端返回的数据中包含code,那么不需要做通用处理,需要各个页面做特殊处理
                var msg = resp.data.msg || "系统错误";
                Message.error(msg);
            } else if (status === 403) {
                Message.error("权限不足");
            } else if (status === 404) {
                Message.error("系统异常(404)");
                return Promise.reject("系统异常(404)");
            } else {
                Message.error(resp.data.error_description);
            }
            return Promise.reject(resp.data);
        }
    );

当然具体实现要根据实际业务场景及前后端交互时的接口方式,以上代码仅供参考。

请求的示例如下:

单相变三相原理模电_默认市值单偏离点差是什么意思_单点登录原理

带token的请求示例

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注