黑狐家游戏

oauth2 前后端分离,oauth2前后端分离单点登录原理

欧气 3 0

标题:OAuth2 前后端分离单点登录原理深度解析

一、引言

在当今的互联网应用中,前后端分离架构已成为主流,这种架构将前端和后端的职责进行了清晰的划分,使得开发和维护更加高效,随之而来的问题是用户认证和授权的复杂性增加,单点登录(Single Sign-On,SSO)技术应运而生,它允许用户只需登录一次,就可以访问多个相关的应用系统,OAuth2 是一种广泛使用的授权框架,特别适用于前后端分离的架构,本文将深入探讨 OAuth2 前后端分离单点登录的原理。

二、OAuth2 基本概念

OAuth2 是一个开放标准,用于授权第三方应用访问用户资源,它定义了四种授权类型:授权码模式、密码模式、客户端凭证模式和简化模式,在前后端分离的架构中,通常使用授权码模式。

授权码模式的流程如下:

1、用户访问客户端应用,客户端应用引导用户到授权服务器进行登录。

2、用户在授权服务器上输入用户名和密码进行登录。

3、授权服务器验证用户身份后,生成授权码,并将其重定向到客户端应用。

4、客户端应用接收到授权码后,使用它向授权服务器换取访问令牌和刷新令牌。

5、客户端应用使用访问令牌向资源服务器请求用户资源。

6、资源服务器验证访问令牌的有效性后,返回用户资源。

三、前后端分离单点登录原理

在前后端分离的架构中,单点登录的实现需要考虑以下几个方面:

1、用户认证:用户在前端应用上输入用户名和密码进行登录,前端应用将用户信息发送到后端应用进行认证,后端应用使用用户信息在数据库中查询用户是否存在,并验证密码是否正确,如果用户认证成功,后端应用生成一个访问令牌,并将其返回给前端应用。

2、访问令牌管理:访问令牌是用户访问资源的凭证,它具有一定的有效期,后端应用需要管理访问令牌的生成、存储、更新和过期处理,访问令牌会存储在数据库中或者使用缓存技术进行存储。

3、前端存储:前端应用需要存储访问令牌,以便在后续的请求中使用,访问令牌会存储在本地存储或者会话存储中,前端应用在每次请求资源时,都会从存储中获取访问令牌,并将其添加到请求头中。

4、资源服务器验证:资源服务器在接收到前端应用的请求时,会验证访问令牌的有效性,如果访问令牌有效,资源服务器会返回用户资源,如果访问令牌无效,资源服务器会返回错误信息。

5、单点登录实现:单点登录的实现需要确保用户在登录一次后,就可以访问所有相关的应用系统,单点登录的实现需要使用会话共享或者令牌共享技术,会话共享是指将用户的会话信息存储在共享的存储中,以便在不同的应用系统中共享,令牌共享是指将用户的访问令牌存储在共享的存储中,以便在不同的应用系统中共享。

四、OAuth2 前后端分离单点登录实现

下面是一个简单的 OAuth2 前后端分离单点登录的实现示例:

1、后端应用

- 安装依赖:npm install express passport passport-oauth2-client-password

- 创建用户模型:models/user.js

```javascript

const mongoose = require('mongoose');

const Schema = mongoose.Schema;

const userSchema = new Schema({

username: String,

password: String

});

module.exports = mongoose.model('User', userSchema);

```

- 创建用户控制器:controllers/user.js

```javascript

const User = require('../models/user');

const passport = require('passport');

exports.login = (req, res, next) => {

const username = req.body.username;

const password = req.body.password;

User.findOne({ username }, (err, user) => {

if (err) {

return next(err);

}

if (!user) {

return res.status(401).json({ error: 'Invalid username or password' });

}

if (user.password!== password) {

return res.status(401).json({ error: 'Invalid username or password' });

}

const accessToken = generateAccessToken(user._id);

res.json({ accessToken });

});

};

const generateAccessToken = (userId) => {

// 生成访问令牌

return 'access_token_' + userId;

};

```

- 创建 passport 策略:passport/local.js

```javascript

const User = require('../models/user');

const passport = require('passport');

passport.use(new passport.LocalStrategy({

usernameField: 'username',

passwordField: 'password'

}, (username, password, done) => {

User.findOne({ username }, (err, user) => {

if (err) {

return done(err);

}

if (!user) {

return done(null, false, { error: 'Invalid username or password' });

}

if (user.password!== password) {

return done(null, false, { error: 'Invalid username or password' });

}

return done(null, user);

});

}));

```

- 创建路由:routes/auth.js

```javascript

const express = require('express');

const router = express.Router();

const passport = require('passport');

router.post('/login', passport.authenticate('local'), (req, res) => {

res.json(req.user);

});

module.exports = router;

```

- 启动后端应用:app.js

```javascript

const express = require('express');

const app = express();

const passport = require('passport');

const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost/oauth2-sso', { useNewUrlParser: true, useUnifiedTopology: true });

app.use(express.json());

app.use(passport.initialize());

app.use(passport.session());

app.use('/auth', require('./routes/auth'));

passport.serializeUser((user, done) => {

done(null, user._id);

});

passport.deserializeUser((id, done) => {

User.findById(id, (err, user) => {

done(err, user);

});

});

app.listen(3000, () => {

console.log('Server started on port 3000');

});

```

2、前端应用

- 安装依赖:npm install axios

- 创建登录组件:Login.jsx

```javascript

import React, { useState } from'react';

import axios from 'axios';

const Login = () => {

const [username, setUsername] = useState('');

const [password, setPassword] = useState('');

const [error, setError] = useState(null);

const handleSubmit = async (e) => {

e.preventDefault();

try {

const response = await axios.post('/auth/login', { username, password });

localStorage.setItem('accessToken', response.data.accessToken);

// 跳转到首页

window.location.href = '/';

} catch (err) {

setError(err.response.data.error);

}

};

return (

<form onSubmit={handleSubmit}>

<input type="text" placeholder="Username" value={username} onChange={(e) => setUsername(e.target.value)} />

<input type="password" placeholder="Password" value={password} onChange={(e) => setPassword(e.target.value)} />

<button type="submit">Login</button>

{error && <p>{error}</p>}

</form>

);

};

export default Login;

```

- 创建首页组件:Home.jsx

```javascript

import React from'react';

const Home = () => {

return (

<div>

<h1>Home</h1>

</div>

);

};

export default Home;

```

- 创建路由:routes/index.jsx

```javascript

import React from'react';

import { BrowserRouter as Router, Route } from'react-router-dom';

import Login from './Login';

import Home from './Home';

const Routes = () => {

return (

<Router>

<Route path="/" exact component={Login} />

<Route path="/home" component={Home} />

</Router>

);

};

export default Routes;

```

- 配置 axios:axios.js

```javascript

import axios from 'axios';

axios.defaults.baseURL = 'http://localhost:3000';

export default axios;

```

- 跳转到首页:index.jsx

```javascript

import React from'react';

import ReactDOM from'react-dom';

import './index.css';

import Routes from './routes';

import { setAccessToken } from './utils/auth';

const accessToken = localStorage.getItem('accessToken');

if (accessToken) {

setAccessToken(accessToken);

}

ReactDOM.render(<Routes />, document.getElementById('root'));

```

- 创建工具函数:utils/auth.js

```javascript

const setAccessToken = (accessToken) => {

axios.defaults.headers.common['Authorization'] =Bearer ${accessToken};

};

export default {

setAccessToken

};

```

五、结论

OAuth2 是一种广泛使用的授权框架,特别适用于前后端分离的架构,在前后端分离的架构中,单点登录的实现需要考虑用户认证、访问令牌管理、前端存储、资源服务器验证和单点登录实现等方面,本文详细介绍了 OAuth2 前后端分离单点登录的原理,并给出了一个简单的实现示例,希望本文能够帮助读者更好地理解 OAuth2 前后端分离单点登录的实现。

标签: #OAuth2 #前后端分离 #单点登录 #原理

黑狐家游戏
  • 评论列表

留言评论