はじめに
Laravel を使用すると、認証の実装が非常に簡単になります。実際、アプリケーションのビジネスに適した非常に包括的な設定項目のセットが提供されます。認証構成ファイルは config/auth.php ディレクトリに保存されます。ここでの各オプションは、完全な注釈ドキュメントを提供します。ここから認証サービスの動作を調整できます。laravel では、認証サービスの中核はガードとプロバイダーで構成されます。ガードは、リクエストからユーザーを認証する方法を定義します。たとえば、laravel にはセッション ガードとトークン ガードが付属しています。セッション ガードは、保存されたセッションと Cookie からのユーザーを認証します。一方、トークン ガードは、API の API トークンを使用してユーザーを認証します。ユーザ認証。
プロバイダーは、永続ストレージからユーザーを取得する方法を定義します。 Laravel 自体は、Eloquent とデータベース クエリ ビルダーという 2 つの取得メソッドを提供します。もちろん、これを行うために追加のプロバイダーを追加することもできます。
これが少しわかりにくいと思われても、心配しないでください。ほとんどのアプリケーションでは、認証サービスのデフォルト構成情報を変更する必要はまったくありません。
データベースノート
デフォルトでは、laravel には AppUser Eloquent モデルがアプリディレクトリに含まれています。このモデルは、デフォルトの Eloquent 認証ドライバーを使用します。アプリケーションが Eloquent ドライバーを使用しない場合は、Laravel のクエリ ビルダーに基づくデータベース認証ドライバーを使用できます。
AppUser モデルのデータベース テーブル構造を構築するときは、パスワードの長さが少なくとも 60 文字に保たれるようにする必要があり、デフォルトの 255 文字を選択することをお勧めします。
また、users テーブルに null 許容文字列列 remember_token が含まれていることを確認する必要があります。この列の長さは 100 文字である必要があります。このフィールドは、ユーザーが長期ログインを維持するためのトークン値を保存するために使用されます。移行で $table->rememberToken() を使用すると、この列をすばやく追加できます。
クイックスタート
Laravel は、AppHttpControllersAuth 名前空間に保存されている認証用の 2 つのコントローラーを読み込みます。 AuthController はユーザー登録と認証のロジックを処理するために使用され、PasswordController にはユーザーがパスワードを取得するための関連ロジックが含まれています。各コントローラーには、特性を導入することで必要なメソッドが含まれています。ほとんどのアプリケーションでは、これらのコントローラーを変更する必要はまったくありません。
ルーティング
laravel は、認証ルーティングを生成し、スキャフォールディングを表示する簡単な方法を提供します:
php artisan make:auth新しいアプリケーションでは、このコマンドは、すべての認証関連の登録ビューとログイン ビューをインストールするために使用されます。ルートも注入されます。 HomeControllerも生成されます。このコントローラーは、ログイン後のリクエストを処理するためのメソッドを提供します。必要に応じて、このコントローラーを削除または変更することもできます。
ビュー
上で述べたように、php 職人の make:auth コマンドは、認証関連のすべてのビューを作成し、resources/views/auth ディレクトリに保存します。
make:auth コマンドは、resoucres/views/layouts ディレクトリも作成し、このディレクトリにアプリケーションの基本レイアウトを作成します。これらのビューはすべて、Bootstrap CSS フレームワークを使用しており、独自のニーズに応じてカスタマイズできます。
認証を実行する
認証関連のコントローラー、ルート、ビューを用意したので、アプリケーションは登録して認証できるようになります。ブラウザを通じてアプリケーションにアクセスでき、認証コントローラーには、ユーザーを認証し、(特性を介して) ユーザーをデータベースに保存するためのすべてのメソッドがすでに含まれています。
カスタム リダイレクト アドレス
ユーザーが認証されると、/ URL にリダイレクトされます。 AuthController コントローラーで redirectTo 属性を定義することで、リダイレクト アドレスを変更できます。
protected $rediredtTo = '/home';ユーザーが正常に認証されなかった場合、ログイン アドレスにリダイレクトされます。
カスタマイズされたガード
ユーザーを認証するためにガードをカスタマイズすることもできます。 AuthControllerにguard属性を定義する必要があります。その値は、auth.php 設定のガード値の 1 つと一致する必要があります:
protected $guard = 'admin';カスタム検証/ストレージ
ユーザーが登録するときに、その他の必要なフォーム フィールドを保存し、新しいユーザーの情報を次の場所に保存することもできます。この時点で、ユーザーの作成とフォームの検証を担当する AuthController クラスを変更する必要があります。
AuthController クラスの validate メソッドを使用して、検証フォームが検証ルールに一致することを確認します。このメソッドは必要に応じて変更できます。
AuthController クラスの create メソッドを使用して、データベースに新しいユーザー レコードを追加します。ここでは Eloquent ORM が使用されます。ニーズに合わせてこのメソッドを変更できます。
認証されたユーザーを取得する
認証マスクを通じて認証されたユーザーにアクセスできます:
$user = Auth::user();また、ユーザーが認証されると、IlluminateHttpRequest のインスタンスを通じて認証されたユーザーにアクセスできます。タイプヒント付きクラスはコントローラーのメソッドに自動的に挿入されることを覚えておいてください。
<?phpnamespace App\Http\Controllers;use Illuminate\Http\Request;class ProfileController extends Controller{ /** * Update the user's profile * * @param Request $request * @return Response */ public function updateProfile(Request $request) { if ($request->user()) { // $request->user() returns an instance of the authenticated user... } }}
判断当前用户是否已被认证
你可以通过 Auth 假面的 check 方法来判断当前用户是否已经被认证。如果该用户已经被认证则会返回 true:
if (Auth::check()) { // The user is logged in...}
你应该使用中间件来过滤未被认证的用户访问某些路由或控制器。
保护路由
路由中间件可以被用来限制只有已经被认证的用户才能访问所给定的路由。laravel 自带了 auth 中间件,该中间件被定义在 app\Http\Middleware\Authenticate.php 文件中。你只需要在定义路由时附加上该中间件就可以了:
// Using A Route Closure...Route::get('profile', ['middleware' => 'auth', function () { // Only authenticated users may enter... }]);// Using A Controller...Route::get('profile', [ 'middleware' => 'auth', 'uses' => 'ProfileController@show']);
当然,如果你使用控制器来注册路由,你可以在控制器的构造函数中使用 middleware 方法来附加中间件:
public function __construct(){ $this->middleware('auth');}
指定守卫
当你附加 auth 中间件到路由时,你也可以指定选择哪个守卫去提供认证:
Route::get('profile', [ 'middleware' => 'auth:api', 'uses' => 'ProfileController@show']);
所指定的守卫应该与配置文件 auth.php 中的 guards 数组键之一相匹配。
认证节流
如果你使用了 laravel 內建的 AuthController 类,那么 Illuminate\Foundation\Auth\ThrottlesLogins trait 可以被用来限制用户尝试登陆的次数。默认的,当用户进行登陆数次失败时,其将会在一分钟内无法进行登陆。节流是根据用户的 username / e-mail 和 IP 地址来判定的:
<?phpnamespace App\Http\Controllers\Auth;use App\User;use Validator;use App\Http\Controllers\Controller;use Illuminate\Foundation\Auth\ThrottlesLogins;use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;class AuthController extends Controller{ use AuthenticatesAndRegistersUsers, ThrottlesLogins; // Rest of AuthController class...}
手动进行用户认证
当然,你没有必要一定使用 laravel 內建的认证控制器。如果你选择删除这些认证控制器,那么你需要直接的使用 laravel 认证类来管理用户的认证。别担心,这当然不在话下。
我们将通过 Auth 假面来访问 laravel 的认证服务,所以,我们要确保在类文件的顶部引入 Auth 假面。接着,让我们查看一下 attempt 方法:
<?phpnamespace App\Http\Controllers;use Auth;class AuthController extends Controller{ /** * Handle an authentication attempt. * * @return Response */ public function authenticate() { if (Auth::attempt(['email' => $email, 'password' => $password])) { // Authentication passed... return redirect()->intended('dashboard'); } }}
attempt 方法接收一个键值对数组来作为第一个参数。数组中的值用来在数据库中查找相匹配的用户。所以,在上面的例子中,会返回匹配到 email 列为 $email 的用户。如果用户被找到,存储在数据库中的哈希后的密码会和数组中经过哈希加密的 password 值进行匹配。如果两个哈希后的值匹配成功的话,就会开启一个该用户已经认证的会话。
如果认证成功,则 attempt 方法会返回 true。否则返回 false。
intended 方法用来返回给重定向器用户在登录前所想要前往的 URL 地址,该方法也接收一个参数作为所请求地址不可用时的备用地址。
指定额外的认证信息
如果你需要,你也可以增加一些额外条件做认证查询,比如,你需要验证被标记为 'active' 的用户:
if (Auht::attempt(['email' => $email, 'password' => $password, 'active' => 1])) { // The user is active, not suspended, and exists.}
注意,在上面的例子中 email 并不是必备的选项,这仅仅只是作为一个示例。你可以使用任何进行用户认证的凭证来映射数据库中的字段。
访问指定的守卫实例
你可以使用 Auth 假面的 guard 方法来获取你所需要的守卫实例。这使你可以在同一个应用中管理多种认证模型或用户表,并实现独立的认证。
guard 方法中所传递的守卫名称应该与配置文件 auth.php 中 guards 之一相匹配:
if (Auth::guard('admin')->attempt($credentials)) { //}
登出
你可以使用 Auth 假面的 logout 方法来进行用户的退出,该方法将清除用户认证的会话信息:
Auth::logout();
记住用户
如果你想要在你的应用中提供 记住我 的功能,你只需要在 attempt 方法中传递一个布尔值作为第二个参数,这将保持用户的认证信息直到用户手动的退出登录。当然,这要求你的用户表中必须包含 remember_token 列:
if (Auth::attempt(['email' => $email, 'password' => $password], $remember)) { // The user is being remembered...}
如果你作为被记住的用户登录的,那么你可以使用 viaRemember 方法来判断用户的认证是不是通过 记住我 的 cookie:
if (Auth::viaRemember()) { //}
其它认证方法
通过用户实例进行认证
如果你需要在应用中记录一个已经存在的用户实例,你可以使用 login 方法。所给定的参数必须是实现了 Illuminate\Contracts\Auth\Authenticatable 契约的一个实例。当然,在 laravel 中 App\User 模型已经实现了这个接口:
Auth::login($user);
当然,你也可以指定守卫实例:
Auth::guard('admin')->login($user);
通过用户ID直接认证
你可以使用 loginUseingId 方法来通过 ID 记录用户的信息,该方法简单的接收一个需要进行认证的用户的主键:
Auth::loginUsingId(1);
仅认证用户一次
once 方法只在当前请求中进行用户认证。不会存储会话或 cookies。这对构建无状态的 API 很有帮助。once 方法和 attempt 具有相同的签证方式:
if (Auth::once($credentials)) { //}
基于 HTTP 的认证
基于 HTTP 的认证提供了快速的用户认证机制而不用设立专门的登录页面。为了开始,你应该附加 auth.basic 中间件到你的路由。laravel 中內建了 auth.basic 中间件,所以你不需要去定义它:
Route::get('profile', ['middleware' => 'auth.basic', function () { // Only authenticated users may enter... }]);
一旦该中间件被附加到路由中,你每次访问该路由时都会被提示要求认证信息。默认的,auth.basic 中间件使用 email 列作为用户记录的用户名。
FastCGI 提示
如果你使用 PHP FastCGI,基于 HTTP 的认证可能无法正常工作。你可以尝试在 .htaccess 文件中添加如下内容:
RewriteCond %{HTTP:Authorization} ^(.+)$RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
无状态的 HTTP 基本认证
你也可以在使用 HTTP 基本认证时不使用 session 保存用户的身份到 cookie。这在基于 API 的认证尤其有效。为了做到这些,你可以定义一个中间件,然后调用 onceBasic 方法。如果 onceBasic 方法没有返回响应,那么请求将被进一步传递到应用:
<?phpnamespace Illuminate\Auth\Middleware;use Auth;use Closure;class AuthenticateOnceWithBasicAuth{ /** * Handle on incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { return Auth::onceBasic() ?: $next($request); }}
接着,在路由中附加中间件:
Route::get('api/user', ['middleware' => 'auth.basic.once', function () { // Only authenticated users may enter... }]);
当然,你还需要在 kernel.php 核心中注册该中间件。
密码重置
数据库注意事项
大多数的应用都提供了一种用户重置其忘记密码的方式。laravel 提供了一种便利的方式来发送密码提示和提供密码重置,这样你就不需要被迫在每个应用都实现一次这种机制。
为了方便开始,请确定你的 App\User 模型实现了 Illuminate\Contracts\Auth\CanResetPassword 契约,laravel 中自带的 App\User 模型中已经实现了这个借口,并且使用了 Illuminate\Auth\Passwords\CanResetPassword trait。
通过迁移生成密码重置表
接着,必须要创建一个用来存储重置密码的 token 的表。laravel 已经提供了这种表的迁移,并且存放在 database/migrations 目录下,所以,你只需要执行迁移命令:
php artisan migrate
路由
laravel 自带的 Auth\PasswordController 控制器包含了所有重置密码所需的逻辑。所有提供密码重置的路由都可以通过 make:auth Artisan 命令来生成:
php artisan make:auth
视图
当 make:auth 命令被执行时,laravel 会生成所有密码重置所需要的视图。这些视图将被存放在 resources/views/auth/passwords 目录中,你可以根据自己的需求去修改。
重置密码之后
一旦你生成了所有重置密码所需要的路由和视图之后,你就可以通过在浏览器访问 /password/reset 路由来进行密码重置。PasswordController 已经包含了发送重置密码的链接邮件及更新密码到数据库的功能。
当密码被重置之后,用户会自动登录并且被重定向到 /home。你可以在 PasswordController 中定义 redirectTo 属性来定制化重定向地址:
protected $redirectTo = '/dashboard';
注意,默认的,密码重置的 token 有效期只有一个小时,你可以在 config/auth.php 配置文件中修改 expire 选项。
定制
定制化认证守卫
在 auth.php 配置文件中,你可以配置多种 "guards",用于对各种用户表执行认证动作。你可以在 PasswordController 中使用 $guard 属性来选择守卫:
/** * The authentication guard that should be used. * * @var string */ protected $guard = 'admins';
定制化密码经纪人
在 auth.php 配置文件中,你可以配置多种密码“brokers”,用于对多种用户表进行密码重置。你可以通过在 PasswordController 中添加 $broker 属性来选择:
/** * The password broker that should be used. * * @var string */ protected $broker = 'admins';
添加自定义的守卫
你可以在服务容器中使用 Auth 假面的 extend 方法来定义自己的认证守卫:
<?phpnamespace App\Providers;use Auth;use App\Services\Auth\JwtGuard;use Illuminate\Support\ServiceProvider;class AuthServiceProvider extends ServiceProvider{ /** * Perform post-registration booting of services. * * @return void */ public function boot() { Auth::extend('jwt', function($app, $name, array $config) { // Return an instance of Illuminate\Contracts\Auth\Guard... return new JwtGuard(Auth::createUserProvider($config['provider'])); }); } /** * Register bindings in the container. * * @return void */ public function register() { // }}
你应该能从上面的示例中看到,你应该在 extend 方法中返回一个 Illuminate\Contracts\Auth\Guard 的实现。为了定制化守卫你需要实现这个接口所包含的方法。
一旦你的守卫被定义,你就可以在 auth.php 配置文件的 guards 选项中进行配置:
'guards' => [ 'api' => [ 'driver' => 'jwt', 'provider' => 'users' ],];
添加自定义的用户提供者
如果你并没有使用传统的关系数据库来存储你的用户,那么你需要提供你自己的用户提供者来扩展 laravel。你可以通过使用 Auth 假面的 provider 方法来定义自己的用户提供者。你应该在服务提供者中调用该方法:
<?phpnamespace App\Providers;use Auth;use App\Extensions\RiakUserProvider;use Illuminate\Support\ServiceProvider;class AuthServiceProvider extends ServiceProvider{ /** * Perform post-registration booting of services. * * @return void */ public function boot() { Auth::provider('riak', function($app, array $config) { // Return an instance of Illuminate\Contracts\Auth\UserProvider... return new RiakUserProvider($app['riak.connection']); }); } /** * Rigster bindings in the container. * * @return void */ public function register() { // }}
在你使用 provider 方法注册完成提供者之后,你需要在 config/auth.php 配置文件中切换你的用户提供者为新注册的提供者:
'providers' => [ 'users' => [ 'driver' => 'riak', ],],
然后,你需要在 guards 选项中使用该提供者:
'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ],],
用户提供者契约
Illuminate\Contracts\Auth\UserProvider 的实现仅仅只是管理如何从持续存储系统中获取一个 Illuminate\Contracts\Auth\Authenticatable 的实现。如 MySQL,Riak,等等。这个两个接口实现了 laravel 的持续认证机制而不需要考虑用户数据是存放在哪里了或者存放的是什么类型。
让我们来看一下 Illuminate\Contracts\Auth\UserProvider 契约:
<?phpnamespace Illuminate\Contracts\Auth;interface UserProvider { public function retrieveById($identifier); public function retrieveByToken($identifier, $token); public function updateRememberToken(Authenticatable $user, $token); public function retrieveByCredentials(array $credentials); public function validateCredentials(Authenticatable $user, array $credentials);}
retrieveById 方法用来接收一个键来返回一个用户,如 MySQL 数据库中自增的主键 ID。被匹配的 ID 应该返回一个 Authenticatable 的实现。
retrieveByToken 方法接收用于识别用户身份的唯一标识 $identifier 和 remember_token 所存储“记住我”的 $token。就如上面的方法一样,该方法应该返回一个 Authenticatable 的实现。
updateRememberToken 方法使用新的 $token 来更新用户的 remember_token 字段。这个新的字段可以是用户登录成功并且设置了 记住我 而分配的,也可以是用户登出之后分配的 null。
retrieveByCredentials 方法接收一个数组凭证,它会在用户尝试登录时将凭证传递给 Auth::attemp 方法。该方法会询问底层持续存储设备凭证的匹配情况,一般该方法会使用 where 条件语句来进行查询 $credentials['username'] 类似的匹配状况。这个方法应该返回一个 UserInterface 的实现。不要在这个方法里做密码验证或者认证。
validateCredentials 方法应该比较所给定的用户和凭证的匹配情况。比如,这个方法或许会比较 $user-getAuthPassword() 和 Hash::make 后的 $credentials['password']。这个方法应该只做用户和凭证间的效验和返回比较情况的布尔值。
可认证的(Authenticatable)契约
刚才我们探讨了 UserProvider 中的所有方法,现在让我们来看一看 Authenticatable 契约,你应该记得,提供者应该从 retrieveById 和 retrieveByCredentials 方法中返回该契约接口的实现:
<?phpnamespace Illuminate\Contracts\Auth;interface Authenticatable { public function getAuthIdentifierName(); public function getAuthIdentifier(); public function getAuthPassword(); public function getRememberToken(); public function setRememberToken($value); public function getRememberTokenName();}
这个接口相对来说非常简单。getAuthIdentifierName 方法应该返回用户的主键字段的名称。getAuthIdentifier 方法应该返回用户的主键。在 MySQL 中,这个主键一般为自增长的主键值。getAuthPassword 应该返回用户的经哈希后的密码。这个接口使认证系统可以在任何用户类中运行而不用管你使用的是什么 ORM 或者其它存储抽象层。默认的,laravel 在 app 目录下包含了 User 类,该类就实现了这个契约。所以你可以参照这个类的实现方式。
事件
laravel 在认证进程中提供了各种各样的事件。你可以在你的 EventServiceProvider 中附加监听这些事件:
/** * The event listener mappings for the application. * * @var array */ protected $listen = [ 'Illuminate\Auth\Events\Attempting' => [ 'App\Listeners\LogAuthenticationAttempt', ], 'Illuminate\Auth\Events\Login' => [ 'App\Listeners\LogSuccessfulLogin', ], 'Illuminate\Auth\Events\logout' => [ 'App\Listeners\logSuccessfulLogout', ], 'Illuminate\Auth\Events\Lockout' => [ 'App\Listeners\LogLockout', ], ];

データベースストレージセッションを使用することの主な利点には、持続性、スケーラビリティ、セキュリティが含まれます。 1。永続性:サーバーが再起動しても、セッションデータは変更されないままになります。 2。スケーラビリティ:分散システムに適用され、セッションデータが複数のサーバー間で同期されるようにします。 3。セキュリティ:データベースは、機密情報を保護するための暗号化されたストレージを提供します。

PHPでのカスタムセッション処理の実装は、SessionHandlerInterfaceインターフェイスを実装することで実行できます。具体的な手順には、次のものが含まれます。1)CussentsessionHandlerなどのSessionHandlerInterfaceを実装するクラスの作成。 2)セッションデータのライフサイクルとストレージ方法を定義するためのインターフェイス(オープン、クローズ、読み取り、書き込み、破壊、GCなど)の書き換え方法。 3)PHPスクリプトでカスタムセッションプロセッサを登録し、セッションを開始します。これにより、データをMySQLやRedisなどのメディアに保存して、パフォーマンス、セキュリティ、スケーラビリティを改善できます。

SessionIDは、ユーザーセッションのステータスを追跡するためにWebアプリケーションで使用されるメカニズムです。 1.ユーザーとサーバー間の複数のインタラクション中にユーザーのID情報を維持するために使用されるランダムに生成された文字列です。 2。サーバーは、ユーザーの複数のリクエストでこれらの要求を識別および関連付けるのに役立つCookieまたはURLパラメーターを介してクライアントに生成および送信します。 3.生成は通常、ランダムアルゴリズムを使用して、一意性と予測不可能性を確保します。 4.実際の開発では、Redisなどのメモリ内データベースを使用してセッションデータを保存してパフォーマンスとセキュリティを改善できます。

APIなどのステートレス環境でのセッションの管理は、JWTまたはCookieを使用して達成できます。 1。JWTは、無国籍とスケーラビリティに適していますが、ビッグデータに関してはサイズが大きいです。 2.cookiesはより伝統的で実装が簡単ですが、セキュリティを確保するために慎重に構成する必要があります。

セッション関連のXSS攻撃からアプリケーションを保護するには、次の測定が必要です。1。セッションCookieを保護するためにHTTPonlyとセキュアフラグを設定します。 2。すべてのユーザー入力のエクスポートコード。 3.コンテンツセキュリティポリシー(CSP)を実装して、スクリプトソースを制限します。これらのポリシーを通じて、セッション関連のXSS攻撃を効果的に保護し、ユーザーデータを確保できます。

PHPセッションのパフォーマンスを最適化する方法は次のとおりです。1。遅延セッション開始、2。データベースを使用してセッションを保存します。これらの戦略は、高い並行性環境でのアプリケーションの効率を大幅に改善できます。

thesession.gc_maxlifettinginttinginphpdethinesthelifsessessiondata、setinseconds.1)it'sconfiguredinphp.iniorviaini_set()。 2)AbalanceSneededToAvoidPerformanceIssues andunexpectedLogouts.3)php'sgarbagecollectionisisprobabilistic、影響を受けたBygc_probabi

PHPでは、session_name()関数を使用してセッション名を構成できます。特定の手順は次のとおりです。1。session_name()関数を使用して、session_name( "my_session")などのセッション名を設定します。 2。セッション名を設定した後、session_start()を呼び出してセッションを開始します。セッション名の構成は、複数のアプリケーション間のセッションデータの競合を回避し、セキュリティを強化することができますが、セッション名の一意性、セキュリティ、長さ、設定タイミングに注意してください。


ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

MantisBT
Mantis は、製品の欠陥追跡を支援するために設計された、導入が簡単な Web ベースの欠陥追跡ツールです。 PHP、MySQL、Web サーバーが必要です。デモおよびホスティング サービスをチェックしてください。

EditPlus 中国語クラック版
サイズが小さく、構文の強調表示、コード プロンプト機能はサポートされていません

ZendStudio 13.5.1 Mac
強力な PHP 統合開発環境

Safe Exam Browser
Safe Exam Browser は、オンライン試験を安全に受験するための安全なブラウザ環境です。このソフトウェアは、あらゆるコンピュータを安全なワークステーションに変えます。あらゆるユーティリティへのアクセスを制御し、学生が無許可のリソースを使用するのを防ぎます。

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)
