start-kit-symfony/start-bundle

Symfony StartBundle 带用户和安全功能

安装: 245

依赖者: 0

建议者: 0

安全: 0

星标: 3

关注者: 2

分支: 0

公开问题: 0

类型:symfony-bundle

1.1.4 2017-12-16 04:51 UTC

This package is not auto-updated.

Last update: 2024-09-20 08:00:20 UTC


README

Build Status

codecov

Symfony 4 安装指南

  1. 安装包,现在不要执行配方。
composer require start-kit-symfony/start-bundle

  1. 将 API 路由添加到 config -> routes.yaml 中的包
starter_kit_start:
    resource: "@StarterKitStartBundle/Resources/config/routing.yml"
  1. 在 -> config 文件夹中的 bundles.php 中添加 NelmioApiDocBundle
Nelmio\ApiDocBundle\NelmioApiDocBundle::class => ['all' => true],
  1. 在 config 文件夹中添加 nelmio_api_doc.yaml 并粘贴以下内容。
nelmio_api_doc:
    routes:
        path_patterns: # an array of regexps
            - ^/(api(?!-docs))
            - ^/oauth
            - ^/login_check
            - ^/access-tokens


    models: { use_jms: false }
    documentation:
        info:
            title: 'Symfony Starter Api'
            description: 'Our Symfony Starter Kit Api Documentation.'
            version: 1.0.0

  1. 将服务别名添加到 services.yaml 文件中。这是一个临时的解决方案。
Nelmio\ApiDocBundle\ApiDocGenerator: '@nelmio_api_doc.generator'
  1. 添加一个名为 ApiDocController 的控制器类,并添加一个名为 apiDoc 的方法。
<?php

namespace App\Controller;

use Nelmio\ApiDocBundle\ApiDocGenerator;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class ApiDocController extends Controller
{
    /**
     * @var ApiDocGenerator
     */
    private $apiDocGenerator;

    public function __construct(ApiDocGenerator $apiDocGenerator)
    {
        $this->apiDocGenerator = $apiDocGenerator;
    }

    /**
     * @Route(name="api_docs", path="api-docs", methods={"GET"})
     *
     * @param Request $request
     * @return Response
     */
    public function apiDoc(Request $request)
    {
        $spec = $this->apiDocGenerator->generate()->toArray();
        if ('' !== $request->getBaseUrl()) {
            $spec['basePath'] = $request->getBaseUrl();
        }

        return $this->render('@NelmioApiDoc/SwaggerUi/index.html.twig', ['swagger_data' => ['spec' => $spec]]);
    }
}
  1. 在您的 var 文件夹中创建一个 jwt 目录
mkdir var/jwt
  1. 使用您使用的密码短语创建您的私钥并记下。
openssl genrsa -out var/jwt/private.pem -aes256 4096
  1. 创建您的公钥,您将需要在这里以及在 composer 安装步骤中使用密码短语。
openssl rsa -pubout -in var/jwt/private.pem -out var/jwt/public.pem
  1. 在您的 App -> Entity 文件夹中创建一个 User 类,该类继承自 BaseUser

  2. 当您创建您的 s3 存储桶时,您需要为每个环境创建一个文件夹。在该文件夹中,您需要添加另一个名为 profile_pics 的文件夹,这是存储个人图片的地方。例如,您有 dev 和 prod。您可以覆盖此设置或选择不使用 s3。

    prod -> profile_pics dev -> profile_pics

  3. 在 .env 文件中填写所有设置服务参数的信息。

###> start-kit-symfony/start-bundle ###

# The Secret Pass
JWS_PASS_PHRASE=secret_change
JWS_TTL=5184000
REFRESH_TOKEN_TTL=10368000

# Facebook Config
FACEBOOK_APP_SECRET=facebook_secret
FACEBOOK_APP_ID=facebook_app_id
FACEBOOK_API_VERSION=2.10
# Google
GOOGLE_CLIENT_ID=google_client_id

# Amazon
AWS_KEY=amazon_key
AWS_SECRET=amazon_secret
AWS_REGION=us-west-2
AWS_BUCKET=fake-bucket
AWS_VERSION=2006-03-01

# Slack
SLACK_CLIENT_KEY=slack_client_key
SLACK_CLIENT_ID=slack_client_id

###< start-kit-symfony/start-bundle ###

APP_EMAIL=fake_email@gmail.com
  1. 在 App 中创建一个名为 "Entity" 的文件夹,并在其中创建一个名为 User 的实体类。
<?php
namespace AppBundle\Entity;
use StarterKit\StartBundle\Entity\BaseUser;
use Doctrine\ORM\Mapping as ORM;
use StarterKit\StartBundle\Entity\FacebookTrait;
use StarterKit\StartBundle\Entity\GoogleTrait;
use StarterKit\StartBundle\Entity\ImageTrait;
use StarterKit\StartBundle\Entity\RefreshTokenTrait;
use StarterKit\StartBundle\Entity\SlackTrait;
/**
 * @ORM\Entity(repositoryClass="StarterKit\StartBundle\Repository\UserRepository")
 * @ORM\Table(name="User")
 * @ORM\HasLifecycleCallbacks()
 * @ORM\Table(name="User", indexes={
 *     @ORM\Index(name="idk_email", columns={"email"}),
 *     @ORM\Index(name="idk_google_user_id", columns={"google_user_id"}),
 *     @ORM\Index(name="idk_slack_user_Id", columns={"slack_user_id"}),
 *     @ORM\Index(name="idk_facebook_user_id", columns={"facebook_user_id"}),
 *     @ORM\Index(name="idk_forget_password_token", columns={"forget_password_token"}),
 *     @ORM\Index(name="idk_refresh_token", columns={"refresh_token"})
 * })
 * Class User
 * @package AppBundle\Entity
 */
class User extends BaseUser
{
    use ImageTrait;
    use GoogleTrait;
    use FacebookTrait;
    use SlackTrait;
    use RefreshTokenTrait;
}
  1. 注册防火墙和安全提供者配置 -> packages -> security.yaml for symfony 4。
security:

    encoders:
        AppBundle\Entity\User:
            algorithm: bcrypt
            cost: 12

    # https://symfony.com.cn/doc/current/security.html#b-configuring-how-users-are-loaded
    providers:
        email:
            id: StarterKit\StartBundle\Security\Provider\EmailProviderInterface
        slack:
            id: StarterKit\StartBundle\Security\Provider\SlackProviderInterface
        token:
            id: StarterKit\StartBundle\Security\Provider\TokenProviderInterface
        facebook:
            id: StarterKit\StartBundle\Security\Provider\FacebookProviderInterface
        google:
            id: StarterKit\StartBundle\Security\Provider\GoogleProviderInterface
        refresh:
            id: StarterKit\StartBundle\Security\Provider\RefreshTokenProviderInterface

    role_hierarchy:
        ROLE_ADMIN:  [ROLE_USER, ROLE_ALLOWED_TO_SWITCH]


    firewalls:
        # disables authentication for assets and the profiler, adapt it according to your needs
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false

        facebook:
            pattern: ^/access-tokens/facebook
            stateless: true
            provider: facebook
            guard:
                authenticators:
                    - StarterKit\StartBundle\Security\Guard\LoginGuardInterface

        google:
            pattern: ^/access-tokens/google
            stateless: true
            provider: google
            guard:
                authenticators:
                    - StarterKit\StartBundle\Security\Guard\LoginGuardInterface

        slack:
            pattern: ^/oauth/slack*
            stateless: true
            provider: slack
            guard:
                authenticators:
                    - StarterKit\StartBundle\Security\Guard\OAuthGuardInterface

        refresh:
            pattern: ^/access-tokens/refresh
            stateless: true
            provider: refresh
            guard:
                authenticators:
                    - StarterKit\StartBundle\Security\Guard\LoginGuardInterface

        login:
            pattern: ^/login_check
            stateless: true
            provider: email
            guard:
                authenticators:
                    - StarterKit\StartBundle\Security\Guard\LoginGuardInterface

        api:
            pattern: ^/api*
            anonymous: ~
            stateless: true
            provider: token
            guard:
                authenticators:
                    - StarterKit\StartBundle\Security\Guard\StateLess\ApiGuardInterface

        main:
            pattern: ^/*
            anonymous: ~
            provider: token
            stateless: true
            guard:
                authenticators:
                    - StarterKit\StartBundle\Security\Guard\StateLess\WebsiteGuardInterface

    access_control:
        - { path: ^/admin, roles: ROLE_ADMIN }

Symfony 3 安装指南

  1. 安装包
composer require start-kit-symfony/start-bundle
  1. 将 Bundle 类添加到 app kernel。
    new StarterKit\StartBundle\StarterKitStartBundle(),
  1. 切换到您的项目目录

  2. 在您的 var 文件夹中创建一个 jwt 目录

mkdir var/jwt
  1. 使用您使用的密码短语创建您的私钥并记下。
openssl genrsa -out var/jwt/private.pem -aes256 4096
  1. 创建您的公钥,您将需要在这里以及在 composer 安装步骤中使用密码短语。
openssl rsa -pubout -in var/jwt/private.pem -out var/jwt/public.pem
  1. 在您的 AppBundle -> Entity 文件夹中创建一个 User 类,该类继承自 BaseUser

  2. 当您创建您的 s3 存储桶时,您需要为每个环境创建一个文件夹。在该文件夹中,您需要添加另一个名为 profile_pics 的文件夹,这是存储个人图片的地方。例如,您有 dev 和 prod。您可以覆盖此设置或选择不使用 s3。

    prod -> profile_pics dev -> profile_pics

  3. 在 App 中创建一个名为 "Entity" 的文件夹,并在其中创建一个名为 User 的实体类。

<?php
namespace AppBundle\Entity;
use StarterKit\StartBundle\Entity\BaseUser;
use Doctrine\ORM\Mapping as ORM;
use StarterKit\StartBundle\Entity\FacebookTrait;
use StarterKit\StartBundle\Entity\GoogleTrait;
use StarterKit\StartBundle\Entity\ImageTrait;
use StarterKit\StartBundle\Entity\RefreshTokenTrait;
use StarterKit\StartBundle\Entity\SlackTrait;
/**
 * @ORM\Entity(repositoryClass="StarterKit\StartBundle\Repository\UserRepository")
 * @ORM\Table(name="User")
 * @ORM\HasLifecycleCallbacks()
 * @ORM\Table(name="User", indexes={
 *     @ORM\Index(name="idk_email", columns={"email"}),
 *     @ORM\Index(name="idk_google_user_id", columns={"google_user_id"}),
 *     @ORM\Index(name="idk_slack_user_Id", columns={"slack_user_id"}),
 *     @ORM\Index(name="idk_facebook_user_id", columns={"facebook_user_id"}),
 *     @ORM\Index(name="idk_forget_password_token", columns={"forget_password_token"}),
 *     @ORM\Index(name="idk_refresh_token", columns={"refresh_token"})
 * })
 * Class User
 * @package AppBundle\Entity
 */
class User extends BaseUser
{
    use ImageTrait;
    use GoogleTrait;
    use FacebookTrait;
    use SlackTrait;
    use RefreshTokenTrait;
}
  1. 在 app -> config -> config.yml 文件中配置 Bundle。
starter_kit_start:

    login_url: '%app.login_url%' # this is the path that your login screen is.  This where website guard will nagivate people if login is required and the user is not logged in.

    jws_ttl: '%app.jws_ttl%' # This the number of seconds the jwt token will live
    jws_pass_phrase: '%app.jws_pass_phrase%' # This the pass phrased you used to create jwt private / public keys.
    refresh_token_ttl: '%app.refresh_token_ttl%' # This how long the refresh token will live.

    user_class: '%app.user_class%' # This is concrete class that extends the base user

    facebook_app_secret: '%app.facebook_app_secret%' # This is client secret that you get when you register your website with facebook
    facebook_api_version: '%app.facebook_api_version%' # Facebook Api Version
    facebook_app_id: '%app.facebook_app_id%' # This is your facebook app id

    google_client_id: '%app.google_client_id%' # This is your google client id
 

    # All this information is found when you create the bucket
    aws_api_version: '%app.aws_api_version%' 
    aws_key: '%app.aws_key%'
    aws_secret: '%app.aws_secret%'
    aws_region: '%app.aws_region%' 
    aws_s3_bucket_name: '%app.aws_region%'

    # This client secret / client are found when u register your app with slack
    slack_client_secret: '%app.slack_client_secret%'
    slack_client_id: '%app.slack_client_id%'

  1. 注册防火墙和安全提供者。这将在 app -> config -> security.yml 中。
security:

    encoders:
        AppBundle\Entity\User:
            algorithm: bcrypt
            cost: 12

    # https://symfony.com.cn/doc/current/security.html#b-configuring-how-users-are-loaded
    providers:
        email:
            id: StarterKit\StartBundle\Security\Provider\EmailProviderInterface
        slack:
            id: StarterKit\StartBundle\Security\Provider\SlackProviderInterface
        token:
            id: StarterKit\StartBundle\Security\Provider\TokenProviderInterface
        facebook:
            id: StarterKit\StartBundle\Security\Provider\FacebookProviderInterface
        google:
            id: StarterKit\StartBundle\Security\Provider\GoogleProviderInterface
        refresh:
            id: StarterKit\StartBundle\Security\Provider\RefreshTokenProviderInterface

    role_hierarchy:
        ROLE_ADMIN:  [ROLE_USER, ROLE_ALLOWED_TO_SWITCH]


    firewalls:
        # disables authentication for assets and the profiler, adapt it according to your needs
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false

        facebook:
            pattern: ^/access-tokens/facebook
            stateless: true
            provider: facebook
            guard:
                authenticators:
                    - StarterKit\StartBundle\Security\Guard\LoginGuardInterface

        google:
            pattern: ^/access-tokens/google
            stateless: true
            provider: google
            guard:
                authenticators:
                    - StarterKit\StartBundle\Security\Guard\LoginGuardInterface

        slack:
            pattern: ^/oauth/slack*
            stateless: true
            provider: slack
            guard:
                authenticators:
                    - StarterKit\StartBundle\Security\Guard\OAuthGuardInterface

        refresh:
            pattern: ^/access-tokens/refresh
            stateless: true
            provider: refresh
            guard:
                authenticators:
                    - StarterKit\StartBundle\Security\Guard\LoginGuardInterface

        login:
            pattern: ^/login_check
            stateless: true
            provider: email
            guard:
                authenticators:
                    - StarterKit\StartBundle\Security\Guard\LoginGuardInterface

        api:
            pattern: ^/api*
            anonymous: ~
            stateless: true
            provider: token
            guard:
                authenticators:
                    - StarterKit\StartBundle\Security\Guard\StateLess\ApiGuardInterface

        main:
            pattern: ^/*
            anonymous: ~
            provider: token
            stateless: true
            guard:
                authenticators:
                    - StarterKit\StartBundle\Security\Guard\StateLess\WebsiteGuardInterface

    access_control:
        - { path: ^/admin, roles: ROLE_ADMIN }

项目概述

服务和接口

每个服务都有一个接口,该接口注册为服务。此包仅在类构造函数中使用接口。这意味着要覆盖服务,您只需找到它所实现的接口,并在应用程序包中注册该接口。

以下是一个示例。假设您想使用存储在数据库中的令牌而不是 jwt / jws 令牌。您只需创建一个实现了 AuthTokenServiceInterface 的服务并注册到应用程序包中即可。

服务注册

AppBundle\Service\DatabaseTokenService:
    class: AppBundle\Service\DatabaseTokenService
    arguments:
        $ttl: '%app.jws_ttl%'

StarterKit\StartBundle\Service\AuthTokenServiceInterface: '@AppBundle\Service\DatabaseTokenService'

您可以在 这里 找到实际的类实现。

这是为包注册服务的位置。 services.yml

不使用 JMS Serializer,Symfony Serializer,FOS Rest Bundles

以下是决定不使用这些的原因。

  1. 使用序列化器比输出数组慢
  2. 使用数组和将它们放入JsonResponse中,可以更轻松地进行测试和单元测试。
  3. FOS Rest Bundle配置起来比较复杂,大多数项目都会使用json而不是xml,所以你可以根据这一点来偏置你的API。
  4. 如果你想添加这些,我也认为这些包的作者们做得非常出色。 ;)

无状态认证

我认为PHP会话比较复杂,版本之间差异很大。如果每个请求都有一个表示用户身份的令牌/字符串,那么理解认证会更简单。我相信这也有助于分离关注点,因为客户端负责存储认证令牌,服务器负责验证它。

Ajax登录

我认为使用Ajax登录并只让请求包含客户端存储的用于认证的cookie会更好。这意味着你不需要担心获取最后一个用户名和刷新页面。这也使得保护逻辑更简单,因为每个登录响应都将有一个认证cookie和认证响应。

响应封装

我认为每个响应都应该被封装在一个描述如何解析它的封装器中。这个项目使用的响应字段是元数据和数据。元数据将有一个类型,这将帮助客户端根据这些类型构建解析器。

{
    "meta":...,
    "data":...
}

仅电子邮件登录

我认为电子邮件是登录的最佳方法,而不是用户名。主要原因是它们对于网站来说是唯一的,如果一家网站收购了另一家网站,可以合并。

目录

如何/示例

如何运行测试

确保你的系统中安装了sqlite。这是我们用于测试数据库的。

  1. git clone https://github.com/phptuts/StarterBundleForSymfony.git

  2. 进入你克隆仓库的目录。

  3. 在命令行中运行这个命令。

sh run_tests.sh