how to implement SSO?
server
https://github.com/DAVIDhaker/django-sso
react client:
index.jsx:
import { createBrowserRouter } from "react-router-dom";
import SSO from "./server/auth";
const router = createBrowserRouter([
{
path: "sso/accept",
element: <SSO />,
},
]);
serve/auth.jsx:
import { useNavigate } from "react-router-dom";
export async function fetchAuthInfo(authToken) {
let formData = new FormData();
formData.append("token", process.env.REACT_APP_AUTH_SECRET);
formData.append("authentication_token", authToken);
const response = await fetch(process.env.REACT_APP_AUTH_GET, {
method: "POST",
body: formData,
});
return response.json();
}
async function confirmAuth(authToken) {
let formData = new FormData();
formData.append("token", process.env.REACT_APP_AUTH_SECRET);
formData.append("authentication_token", authToken);
const response = await fetch(process.env.REACT_APP_AUTH_CONFIRM, {
method: "POST",
body: formData,
});
return response.json();
}
export function useToken() {
const getToken = () => {
return localStorage.getItem("token");
};
const [token, setToken] = useState(getToken());
const saveToken = (userToken) => {
localStorage.setItem("token", userToken);
setToken(userToken);
};
return {
setToken: saveToken,
token,
};
}
export function useUser() {
const getUser = () => {
return localStorage.getItem("user");
};
const [user, setUser] = useState(getUser());
const saveUser = (user) => {
localStorage.setItem("user", user);
setUser(user);
};
return {
setUser: saveUser,
user,
};
}
export default function SSO() {
const navigate = useNavigate();
const { token } = useToken();
const { setUser } = useUser();
useEffect(() => {
async function fetchData() {
const response = await fetchAuthInfo(token);
setUser(response.user_identy);
await confirmAuth(token);
navigate(response.next_url);
}
fetchData();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return null;
}
flask client
from functools import wraps
import requests
from flask import Blueprint, current_app, request, session
from . import db
from .models import User
bp = Blueprint('sso', __name__, url_prefix='/sso/')
def auth(view_function):
"""decorator of view function need auth
"""
@wraps(view_function)
def wrapper(*args, **kwargs):
request_token = request.headers.get("Authorization")
if not request_token:
return dict(error="请登录"), 401
username = session.get("username")
if not (request_token == session.get("token") and username):
try:
response = requests.post(
current_app.config["SSO_AUTH_GET_URL"],
data={
"token": current_app.config["SSO_AUTH_SECRET"],
"authentication_token": request_token
},
timeout=5)
except requests.exceptions.ConnectionError:
return dict(error="认证服务连接不上, 请联系管理员"), 401
auth_info = response.json()
if auth_info.get("error"):
return dict(error="认证失败"), 401
username = auth_info["user_identy"]
session["username"] = username
session["token"] = request_token
user = db.session.execute(
db.select(User).filter_by(username=username)).scalar()
if not user:
user = User(username=username)
db.session.add(user)
db.session.commit()
return view_function(*args, **kwargs, user=user)
return wrapper
def permission(role):
"""decorator of view function need permission
"""
def decorator(view_function):
"""decorator
"""
@wraps(view_function)
def wrapper(*args, **kwargs):
if not kwargs.get("user").has_permission(role):
return "您没有权限", 403
return view_function(*args, **kwargs)
return wrapper
return decorator
# `/sso/event/` api can sync data with server:
@bp.route("/event/", methods=("POST", ))
def event():
"""event
"""
data = request.json
event_type = data.get("type")
if event_type == "update_account":
fields = data.get("fields")
username = fields.get("user_identy")
user = db.session.query(User).filter_by(username=username).first()
first_name = fields.get("first_name")
if user:
if first_name != user.first_name:
user.first_name = first_name
db.session.commit()
else:
user = User(username=username, first_name=first_name)
db.session.add(user)
db.session.commit()
return {"ok": True}