赞同 3
分享

我用django-simple-sso做了一个SSO的登陆

简介:工作中经常用到SSO统一登陆,所以我想用django_simple_sso这个三方包学习sso的这个请求过程,然后做一个通用的sso服务。
  2020.08.12
  Bug Man
  3
  444
  172.17.0.1
  中国.上海
 
 

1.安装django-simple-sso: pip install django-simple-sso

2.Server端配置完成simple_sso.sso_server应用的注册后,将对应的数据表迁移到数据库中python manage.py migrate。在数据表sso_server_consumer中添加一条密钥对,随便找两个字符串就像Django中SECRET_KEY差不多,这里我就用简单的字符串代替。如果在django交互界面去创建一条记录:

# 进入django shell
python mange.py shell
# django shell
from simple_sso.sso_server.models import Consumer
Consumer.objects.create(public_key='public', private_key='private', name='basics')

3.配置Server端:

# 注册 simple_sso.sso_server
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'account',
    'simple_sso.sso_server'
]

# 项目同名文件夹下url.py
from django.contrib import admin
from django.urls import path, include
from simple_sso.sso_server.server import Server

from account.views import index
test_server = Server(auth_view_name='account:login')

urlpatterns = [
    path('', index),
    path('admin/', admin.site.urls),
    path('account/', include(('account.urls', 'account'), namespace='account')),
    path('server/', include(test_server.get_urls())),
]

# account应用下url.py
from django.urls import path

from account import views

urlpatterns = [
    path('login/', views.SSOLoginView.as_view(), name='login'),
]

# account/login/ 视图类
class SSOLoginView(LoginView):
    template_name = 'account/login.html'
{% extends 'base.html' %}

{% block title %}
    <title>登陆</title>
{% endblock %}


{% block body %}
    <div class="app">
        <form action="{% url "account:login" %}" method="post">
            {% csrf_token %}
            <div class="row extend-margin">
                <div class="col-xs-12">
                    <div class="form-account">
                        <div class="input-1">
                            <input type="text" class="form-control" name="username" placeholder="请输入邮箱">
                        </div>
                        <div class="input-2"></div>
                        <div class="input-3">
                            <input type="password" class="form-control" name="password" placeholder="请输入密码">
                        </div>
                    </div>
                </div>
            </div>
            <input type="hidden" name="next" value="{{ next }}">
            <div class="row extend-margin">
                <div class="col-xs-12">
                    <div class="extend-operate">
                        <label for="remember"><input type="checkbox" id="remember">记住我</label>
                        <a href="#">忘记密码</a>
                    </div>
                </div>
            </div>
            <div class="row extend-margin">
                <div class="col-xs-12">
                    <div class="account-submit">
                        <input type="submit" class="form-control" value="登录">
                    </div>
                </div>
            </div>
        </form>
    </div>
{% endblock %}

4.配置Client端:

# 注册 simple_sso.sso_client 应用
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'account',
    'simple_sso.sso_client',
]

# 需要用到的一些常量
# django_simple_sso
###########################################
#       SSO
###########################################
SSO_SERVER = 'http://a.cn:8008/server/'
SSO_PUBLIC_KEY = 'public'
SSO_PRIVATE_KEY = 'private'
SSO_CLIENT = 'http://a.cn:8009/'

# 项目同名ulr.py
from django.contrib import admin
from django.shortcuts import redirect
from django.urls import path, include
from simple_sso.sso_client.client import Client

from basics_client import settings

test_client = Client(settings.SSO_SERVER, settings.SSO_PUBLIC_KEY, settings.SSO_PRIVATE_KEY)

urlpatterns = [
    path('', lambda request: redirect('/client/' if not request.user.is_authenticated else 'index/', permanent=False)),
    path('admin/', admin.site.urls),
    path('client/', include(test_client.get_urls())),
    path('index/', include('account.urls')),
]

5.晃晃悠悠做了一天的流程图,掌握这个流程自己写SSO也可以了: SSO流程图

6.client端和server端的验证加密方式:

# pip install itsdangerous
from itsdangerous import TimedSerializer

# Client、Server实例化序列化器
signer = TimedSerializer('private')
s2 = signer.dumps({'target': 'test'})  # '{"target": "test"}.Xzd5YA.qfFLTfpLxh3z8XUOYe8YCZ1ZDZs'
# max_age=5从dumps到loads超过5秒报signer expire
s = signer.loads(s2, max_age=5)  # {'target': 'test'}

7.Server端生成Token:

# 字符串大小写+数字
KEY_CHARACTERS = string.ascii_letters + string.digits
# 创建token
def default_gen_secret_key(length=40):
    return ''.join([random.choice(KEY_CHARACTERS) for _ in range(length)])

# Token model
class Token(models.Model):
    consumer = models.ForeignKey(
        Consumer,
        related_name='tokens',
        on_delete=models.CASCADE,
    )
    request_token = models.CharField(
        unique=True, max_length=64,
        default=TokenSecretKeyGenerator('request_token')
    )
    access_token = models.CharField(
        unique=True, max_length=64,
        default=TokenSecretKeyGenerator('access_token')
    )
    timestamp = models.DateTimeField(default=timezone.now)
    redirect_to = models.CharField(max_length=255)
    user = models.ForeignKey(
        getattr(settings, 'AUTH_USER_MODEL', 'auth.User'),
        null=True,
        on_delete=models.CASCADE,
    )

    def refresh(self):
        self.timestamp = timezone.now()
        self.save()

总结来说,如果你想要做一个SSO先上码云拉一个client和server的案例跑通了,改改就能用的,之后我会分析我们项目里面的接入SSO验证的ModelBackend后端校验类。