I have a nancy module with multiple routes and want to do a security check on a parameter that is shared by each of the routes. Can I somehow move this parameter 'up in the hierachy' and have the check be a single line?
Example provided below
public SomeModule()
{
//ABC
Get["/prefix/{someSharedParameter}/ABC/{noneSharedParameterA}"] = parameters =>
{
this.RequiresSomethingArbitrary(parameters.someSharedParameter);
...
};
//XYZ
Get["/prefix/{someSharedParameter}/XYZ/{noneSharedParameterX}"] = parameters =>
{
this.RequiresSomethingArbitrary(parameters.someSharedParameter);
...
};
}
So I would like to be able to put the check RequiresSomethingArbitrary on module level here but not sure how or if that is even possible.
EDIT: I had an idea after finding out module base path but it came short.
THIS DOES NOT WORK. Context is null.
public SomeModule(): base("/prefix/{someSharedParameter}")
{
this.RequiresSomethingArbitrary(Context.Parameters.someSharedParameter);
//ABC
Get["/ABC/{noneSharedParameterA}"] = parameters =>
{
...
};
//XYZ
Get["/XYZ/{noneSharedParameterX}"] = parameters =>
{
...
};
}
I also tried only doing the check if context is null because I figured it might be failing on initializing the module only but this will just always skip the check:
public SomeModule(): base("/prefix/{someSharedParameter}")
{
if (Context != null) {
//this is unreachable (?)
this.RequiresSomethingArbitrary(Context.Parameters.someSharedParameter);
}
//ABC
Get["/ABC/{noneSharedParameterA}"] = parameters =>
{
public SomeModule(){
this.RequiresSomethingArbitrary(someSharedParameter);
//route definitions go here
}
All you need to do is move the check to the constructor.
Related
Hi i found some bug in my laravel app and wondering how to fix it :/
My controlers code
public function patvirtinimas($id,$bookid)
{
return \View::make('grazintiknyga.patvirtinti',compact('id','bookid'));
}
public function grazintiknygasave($id,$bookid,Request $request)
{
if(Input::get('taip'))
{
$grazinimas = Carbon::now();
$grazinimas->format("Y-m-d");
$kasprieme = Auth::user()->id;
$resetas = NULL;
//dd($kasprieme);
DB::beginTransaction();
try {
DB::table('borrows')
->where('id', $id)
->update(['grazinimo_data' => $grazinimas,
'prieme' => $kasprieme
]);
DB::table('books')
->where('id', $bookid)
->update(['isdavimo_data' => $resetas,
'terminas' => $resetas,
'grazinimo_data' => $resetas
]);
DB::commit();
// jeigu viskas gerai
} catch (\Exception $e) {
DB::rollback();
dd($e);
// jeigu kazkas negerai
}
return \Redirect::to(url('grazinti-knyga'))->with('grazinta','Knyga grąžinta sėkmingai!');
}
elseif(Input::get('ne'))
{
return \Redirect::to(url('grazinti-knyga'))->with('negrazinta','Knygos grąžinimas atšauktas!');
}
}
One function for viewing other for updating tables in db
routes
Route::get('patvirtinti-grazinima-{id}-{bookid}', 'BorrowController#patvirtinimas');
Route::post('grazinimas-save-{id}-{bookid}', 'BorrowController#grazintiknygasave');
The problem is when i edit route directly in my browser grazinimas-save-{someid}-{somebookid}
When one of parameters matches other dont then half of db transaction works and
other doesn't update and destroys my db :? can some one help fix this bugs ? that both parameters must match in db to update. Maybe there is some parameters hidding and validation?
Slashes / are the expected way to separate arguments in your routes.
Your parameters are not getting passed on properly to your Controller.
Changes the routes to the following (if you can)
Route::get('patvirtinti-grazinima/{id}/{bookid}', 'BorrowController#patvirtinimas');
Route::post('grazinimas-save/{id}/{bookid}', 'BorrowController#grazintiknygasave');
Another option is to handle the logic in your Controller or a Middleware (https://laracasts.com/discuss/channels/laravel/using-dash-instead-of-slash-in-routes)
I'm trying to move to another database dynamically. I've seen several questions that showed change db files from one to another and they just getting some information from next database. But what I need is completely moving to second database. How should I do this? I've seen that in order to achieve this dsn (in db.php file) should be altered. But I changed it and it's still not changed?? I should have full access to second database closing first one. Give me advice please
Configs like db.php are not intended to be changed in process (while PHP is processing). They are loaded once in the initialization, when request is entered the framework.
As an alternative, you can configure second DB beforehand in db.php, and change between them dynamically like:
Yii::$app->db // your default Database
and
Yii::$app->db2 // Second configured Database, to which you can switch dynamically later
You can learn about multiple database connections here
So, if you want ActiveRecord(for instance User) to be able to access two databases, you can define some static variable, which specifies from which DB to read/write. For example:
class User extends \yii\db\ActiveRecord
{
const DB_DATABASE1 = 'db1';
const DB_DATABASE2 = 'db2';
private static $db = self::DB_DATABASE1;
public static function setDb($db)
{
self::$db = $db;
}
public static function getDb()
{
switch (self::$db) {
case self::DB_DATABASE1:
return Yii::$app->db;
case self::DB_DATABASE2:
return Yii::$app->db2;
default:
throw new \Exception("Database is not selected");
}
}
//...
And then use it in Controller like:
User::setDb(User::DB_DATABASE1);
$usersDB1 = User::find()->all();
User::setDb(User::DB_DATABASE2);
$usersDB2 = User::find()->all();
Set up multiple database connections in your main.php or main-local.php configuration
Yii::$app->db1;
Yii::$app->db2;
Yii::$app->db3;
when making inquiries
$usersDB1=User::find()->all(Yii::$app->db1);
$usersDB2=User::find()->all(Yii::$app->db2);
$usersDB3=User::find()->all(Yii::$app->db3);
Globally switch to a different database dynamically
I have combined Yerke's answer above and Write & use a custom Component in Yii2.0 here.
First, create a component class to do the DB switching. Here, I call it DbSelector and put it in app\components\DbSelector.php.
namespace app\components;
use Yii;
use yii\base\Component;
use yii\base\InvalidConfigException;
class DbSelector extends Component {
const DB_MAIN = 'db';
const DB_SUB1 = 'db1';
const DB_SUB2 = 'db2';
private static $db = self::DB_MAIN;
public static function setDb($db)
{
self::$db = $db;
}
public static function getDb()
{
return \Yii::$app->get(self::$db);
}
}
Second, modify the config/web.php file or whichever your config file is to have multiple databases and add DbSelector as a Yii::$app component.
$config = [
'components' => [
//...
'db' => $db,
'db1' => $db1,
'db2' => $db2,
'dbSelector' => [
'class' => 'app\components\DbSelector',
],
//...
],
//...
];
Third, in each model class, add the following static function getDb() to call the DbSelector getDb():
public static function getDb()
{
return \Yii::$app->dbSelector->getDb();
}
For example,
class DiningTable extends \yii\db\ActiveRecord
{
public static function tableName()
{
return '{{%dining_table}}';
}
public static function getDb()
{
return \Yii::$app->dbSelector->getDb();
}
//...
}
class Customer extends \yii\db\ActiveRecord
{
public static function tableName()
{
return '{{%customer}}';
}
public static function getDb()
{
return \Yii::$app->dbSelector->getDb();
}
//...
}
Lastly, to globally switch to a different database, use \Yii::$app->dbSelector->setDb(YOUR_PREFERRED_DB),
use app\components\DbSelector;
//...
\Yii::$app->dbSelector->setDb(DbSelector::DB_SUB1);
$tables_1 = DiningTable::findAll();
$customers_1 = Customer::find()->where(['<', 'dob', '2000-01-01'])->all();
\Yii::$app->dbSelector->setDb(DbSelector::DB_MAIN);
$tables_main = DiningTable::findAll();
$customers_main = Customer::find()->where(['<', 'dob', '2000-01-01'])->all();
I'm working on setting up two-factor in my application and I'm trying to make it redirect back to the verification page if the user is logged in but not verified (I'm keeping track of if the user is verified in the sessions table which is added to ClaimsPrincipal 'IsVerified').
The problem i'm having is the example I am using from the documentation doesn't seem to be working properly:
public static class ModuleSecurity
{
public static string[] ExcludedPaths = { "/", "/login", "/login/verify", "/admin/settings", "/login/tf/setup" };
public static void RequiresAuthentication(this NancyModule module)
{
module.Before.AddItemToEndOfPipeline(RequiresAuthentication);
}
private static Response RequiresAuthentication(NancyContext context)
{
// Check if user is authenticated
if (context.CurrentUser == null)
return new Response() { StatusCode = HttpStatusCode.Unauthorized };
if (context.CurrentUser.FindFirst("RequireVerification")?.Value == "True" && context.CurrentUser.FindFirst("IsVerified")?.Value != "True" && !ExcludedPaths.Any(x => x.ToLower() == context.Request.Path.ToLower()))
return new Response().WithHeader("Location", "/login/verify").WithContentType("text/html").WithStatusCode(HttpStatusCode.SeeOther);
return null;
}
}
Putting break points in I see the "module.Before.AddItemToEndOfPipeline" is executed but it is not executing the other method I have.
Then problem was I was adding this to the BEFORE pipeline but i'm calling this.RequiresClaims after the route was triggered (so I needed the AFTER pipeline). I was able to do this by adding the extensions and using the module.AddBeforeOrExecute option.
I would like to inject different strings into each of my module's contructors. I register a factory method which constructs the module. I can then call container.Resolve<T>() and all is well. For some reason though when Nancy tries to resolve my module it throws the error
Nancy.TinyIoc.TinyIoCResolutionException: Unable to resolve type:
Plugin.HomeModule ---> Nancy.TinyIoc.TinyIoCResolutionException:
Unable to resolve type: System.String
public class HomeModule : NancyModule
{
public HomeModule(string text)
{
}
}
protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
base.ConfigureApplicationContainer(container);
container.Register<HomeModule>((ctr, param) => { return new HomeModule("text"); });
HomeModule module = container.Resolve<HomeModule>();
}
I have also tried doing the registration in ConfigureRequestContainer() with the same results. I have tried container.Register<HomeModule>(new HomeModule("some text")); as well as AsSingleton(). I can register an implementation to the string type with container.Register<string>("text"), but this would inject the same string into all modules.
How can I register a module constructor so that Nancy can resolve it?
Modules are obtained through the INancyModuleCatalog, which is normally implemented by the bootstrapper, you'd have to create a custom variation of that - if you're using the default bootstrapper then this is the current implementation:
https://github.com/NancyFx/Nancy/blob/master/src/Nancy/DefaultNancyBootstrapper.cs#L205
The best approach for this would be to not pass in a primitive into your module, but us something richer, or perhaps a factory. The container can resolve those dependencies. Passing a plain string into the module is a sign of a problem somewhere else and a hint that your architecture probably needs rethinking
I have implemented a custom catalog that registeres only Modules of a specific namespace, but I don't know where to register this.
public CustomModuleCatalog()
{
// The license type is read from db in Global.ascx.
// So I want to register a module based on a namespace.
// The namespace is the same like the license name.
if(WebApiApplication.LicenseType == LicenseType.RouteOne)
{
var assemblyTypes = Assembly.GetExecutingAssembly().GetTypes();
var modules = assemblyTypes.Where(t => t.Namespace != null && t.Namespace.EndsWith("MyCustomNamespace"));
var nancy = modules.Where(t => t.IsAssignableFrom(typeof(INancyModule)));
foreach (var type in nancy)
{
var nancyType = (INancyModule)type;
_modules.Add(type, (INancyModule)Activator.CreateInstance(type));
}
}
}
public IEnumerable<INancyModule> GetAllModules(NancyContext context)
{
return _modules?.Values;
}
public INancyModule GetModule(Type moduleType, NancyContext context)
{
if (_modules != null && _modules.ContainsKey(moduleType))
{
return _modules[moduleType];
}
return null;
}
Element file I am calling:
$brand = $this->requestAction('brands/buyer_getnames/');
Action file I am calling:
public function buyer_getnames(){
$newid=$this->Auth->User('brand_id');
$name=$this->Brand->find('first',array('conditions'=>array('Brand.id'=>$newid),'recursive'=>-1));
return $name['Brand']['name'];
}
Getting error below..!!
Private Method in BrandsController
Error: BrandsController::buyer_getnames() cannot be accessed directly.
Please help
Request action respects normal url routing rules
If you're using prefix routing then you can't access function prefix_foo() via a url of the form /controller/prefix_foo - it needs to be the corresponding prefix url: /prefix/controller/foo.
As such your request action call should be:
$brand = $this->requestAction('/prefix/brands/getnames/');
Note that if the only thing that method does is call a model method, you're better off simply doing:
$model = ClassRegistry::init('Brand');
$brand = $model->someMethod();
You can allow unauthorized access to action if your action is requested with requestAction method.
For example:
public function beforeFilter() {
parent::beforeFilter();
if ($this->request->is('requested') && $this->request->params['action'] == 'index') {
$this->Auth->allow(array('index'));
}
}
This may also work (haven't tested):
public function index() {
if ($this->request->is('requested')) {
$this->Auth->allow(array('index'));
}
}
let me know if i can help you more.