I have a typical class like this:
public class A {
void run(); //for all users
void delete(); //for privileged users
}
I want to distribute these classes as a single jar to different users, the common users can only see the methods which is permitted and cannot see these high privileged(like delete()), how can i achieve this?
By the way i am a big fan of DDD, which means i donot want these methods to fall apart.
I end up with this solution:
restrict high privileged method access with private or package access modifier, so common user cannot see them, and privileged user visit these method through reflection.
public class A {
public void run(); //for all users
void delete(); //for privileged users
}
privileged user:
Reflections.invokeMethod(ins,"run");
Without a access modifier (public/protected/private...) it wont be visible
Related
I'm working an a ASP.NET application (not using MVC) and need a User-Role-Permission based authorization scheeme, where pages and/or methods can demand the specific permission they require (instead of which role the user has). Is there a way to extend Forms Authentication (or building something) to solve this?
If possible I would like to be able to use attributes:
[RequirePermission("UserEdit")]
public partial class EditUser : System.Web.UI.Page
{
}
Perhaps even for methods:
public class MyClass
{
...
[RequirePermission("UserEdit")]
public void Save()
{
...
}
}
Is this possible?
I found this page, that suggested using Roles for permissions:
[Authorize(Roles = "UserEdit")]
public partial class EditUser : System.Web.UI.Page
{
}
I am not very fond of this solution, but that would also be a possible way to solve things, but what do I need to do to get it working?
Microsoft's authorization model sucks...and it's widely acknowledged
http://lostechies.com/derickbailey/2011/05/24/dont-do-role-based-authorization-checks-do-activity-based-checks/).
That said. It's nice to have cross compatibility by fitting into their IPrincipal.IsInRole API (and thus being able to leverage the Authorize attribute)
So...what I do to compromise is have a full permission model in the DB with Users, Roles, and Permissions...but when my code sets the CurrentPrincipal I flatten the User's Roles and Permissions into the Roles collection of the IPrincipal. It's far from ideal...but IMHO it's a decent compromise. Others (Rockford Lhotka) have also taken this approach: http://www.lhotka.net/weblog/PermissionbasedAuthorizationVsRolebasedAuthorization.aspx
Let's consider this page's code-behind:
public partial class Products : Page
{
private static SomeClass SharedField;
public Product()
{
// ... Some logic
}
}
Do all Products pages instances share the same SharedField, I know this is a basic concept of static fields. But in this case, really? all users can have access (and can't have their own instance of) to the same static field on the website-level?
If so, in what aspects this would used by the web developer? or is this non-recommended practice?
Yes, there will be a single instance of that static field for all users, but only within a single worker process. If you have web farms/web gardens, they will each have their own static instance. If the worker process restarts, you'll get a new static instance.
You'll have to use locking around that shared field to ensure thread safety.
As for why to use that, I'm not sure, I never do it. The best example I can give you is the built-in static HttpContext.Current, which gives you access to the Request, Response, etc.
SharedField will be available in one instance for the entire life-cycle of the web site.
To read a bit more about it, see this answer.
A better practice would be to store your object in the Application state.
Application["MyObject"] = new SomeClass();
I'm learning EF now and have a question regarding the ObjectContext:
Should I create instance of ObjectContext for every query (function) when I access the database?
Or it's better to create it once (singleton) and reuse it?
Before EF I was using enterprise library data access block and created instance of dataacess for DataAccess function...
I think the most common way is to use it per request. Create it at the beginning, do what you need (most of the time these are operation that require common ObjectContext), dispose at the end. Most of DI frameworks support this scenario, but you can also use HttpModule to create context and place it in HttpContext.Current.Items. That is simple example:
public class MyEntitiesHttpModule : IHttpModule
{
public void Init(HttpApplication application)
{
application.BeginRequest += ApplicationBeginRequest;
application.EndRequest += ApplicationEndRequest;
}
private void ApplicationEndRequest(object sender, EventArgs e)
{
if (HttpContext.Current.Items[#"MyEntities"] != null)
((MyEntities)HttpContext.Current.Items[#"MyEntities"]).Dispose();
}
private static void ApplicationBeginRequest(Object source, EventArgs e)
{
var context = new MyEntities();
HttpContext.Current.Items[#"MyEntities"] = context;
}
}
Definitely for every query. It's a lightweight object so there's not much cost incurred creating one each time you need it.
Besides, the longer you keep an ObjectContext alive, the more cached objects it will contain as you run queries against it. This may cause memory problems. Therefore, having the ObjectContext as a singleton is a particularly bad idea. As your application is being used you load more and more entities in the singleton ObjectContext until finally you have the entire database in memory (unless you detach entities when you no longer need them).
And then there's a maintainability issue. One day you try to track down a bug but can't figure out where the data was loaded that caused it.
Don't use a singleton.. everyone using your app will share that and all sorts of crazy things will happen when that object context is tracking entities.
I would add it as a private member
Like Luke says this question has been asked numerous times on SO.
For a web application, per request cycle seems to work best. Singleton is definitely a bad idea.
Per request works well because one web page has a User, maybe some Projects belonging to that user, maybe some Messages for that user. You want the same ObjectContext so you can go User.Messages to get them, maybe mark some messages as read, maybe add a Project and then either commit or abandon the whole object graph at the completion of the page cycle.
Late post here by 7 months. I am currently tackling this question in my app and I'm leaning towards the #LukLed solution by creating a singleton ObjectContext for the duration of my HttpRequest. For my architecture, I have several controls that go into building a page and these controls all have their own data concerns that pull read-only data from the EF layer. It seems wasteful for them to each create and use their own ObjectContext's. Besides, there are a few situations where one control may pull data into the Context that could be reused by other controls. For instance, in my masterpage, my header at the top of the page has user information that can be reused by the other controls on the page.
My only worry is that I may pull entities into the context that will affect the queries of other controls. I haven't seen that yet but don't know if I'm asking for trouble. I guess we'll see!
public class DBModel {
private const string _PREFIX = "ObjectContext";
// DBModel.GetInstance<EntityObject>();
public static ObjectContext GetInstance<T>() {
var key = CreateKey<T>();
HttpContext.Current.Items[key] = HttpContext.Current.Items[key] ?? Activator.CreateInstance<T>();
return HttpContext.Current.Items[key] as ObjectContext;
}
private static string CreateKey<T>() {
return string.Format("{0}_{1}", _PREFIX, typeof(T).Name);
}
}
We're beginning to design a whole bunch of new services to create (WCF, ADO.NET Data Services, possibly in the cloud at some point) and one question that pops up is what authentication and authorization scheme to use - there are quite a few!
We basically need to be able to identify users (actual people, and "virtual" application/service users) on a wide variety of protocols - HTTP, HTTPS, TCP - and we need to assign them at least a bunch of roles / permission to see certain data and/or do certain operations.
We definitely can't use Windows group membership alone - we have plenty of external consumers of our services and we don't want to have to set up a domain account in our internal domain for everyone of them.
So there's mainly three options, I think:
Using the ASP.NET membership system - create users and assign roles there
Use AzMan (Authorization manager) which seems to be a more granular, more mature, more elaborate system (with users, tasks, groups - three levels, not just user + roles)
Roll our own
First of all - which of these three would you recommend? Any why?
Secondly - are there more options that I'm missing?
Thanks for any hints, pointers, opinions!
Marc
PS: seeing the answers so far, I'm amazed at the amount of folks voting for option #3. I would have thought that MS would be able to design something reusable that could handle all of these requirements....
Actually, the answer is probably a combination of 1 and 3.
You can take advantage of a lot of the tools and features that the framework provides for you by writing a membership, role or profile provider if the default options don't quite go as far as you'd like.
We've done just that on a number of client sites - for example one of our clients has most of their users stored as Commerce Server users, and use the Commerce Server profile system, so we wrote a membership and profile provider to talk to those datastores - a fairly simple excercise.
Most people are probably going for 3 because of the need to authenticate over raw TCP - this introduces a layer beyond that of the standard ASP.NET membership providers.
Most of what MS produce is "ok" or "good enough", but there will always be edge cases where you want to do something "not quite standard" that mean you end up rolling your own. I guess to have something beyond "Basic Auth" or "Windows Auth" that was simple for your average developer to understand, they took the sensible option of "lets just build this for the web".
If you take a look at the numerous ways you can authenticate against a WCF service, you'll see what I mean - these are designed to handle different transport mechanisms, and are therefore much more complex.
That said, the default roles and profile providers are fairly limited (roles: no hierarchy, so you need to check for each possible role, or explicitly assign each role to the user; profiles: all stored in one field as comma seperated values - not easy to find all users who've got a value set).
We use (3). Actually that helped us in an integration scenery to have accounts in sync with
business processes
Other systems (not all on the same technology stack (ASP.NET))
On a recent project we extended the ASP.NET membership provider (wrote a custom provider) with the intent of using some of the role based controls for managing permissions. Now that the project has matured sufficiently, we're finding that the controls are not flexible enough for our requirements, and to some extent we're regretting going down the MS membership path. Rolling your own authentication if you have the time to architect it correctly is going to be the best option.
It sounds like your app is a bit of a hybrid in that you're serving internal and external customers, but perhaps also give some consideration to integrating OpenID for your external customers. There are some great ASP.NET OpenID controls that really makes handling new accounts for external customers a no brainer. This of course depends on how 'public' your application is.
Ldap anyone? It's free, cross-plaftorm, easy to use and administer remotely, has bridges to other auth schemes, and bindings in more languages that you knew existed...
Isn't AZMan from 2003?
I would recommend 1 or 3. Personally I've always gone for 3. There's a lot of functionality that 1 has that I don't use or care to use.
I would stay away from AzMan. We went down that road once and didn't like the section of town we broke down in. We've always done AD-based logins that use the SID of the current user to link to a user in the database, then taken the permissions from there. Given your setup this may not be possible (or practical), but I'd stay away from AzMan in any event.
I'm not an ASP or .NET developer, but my gut says (3). You really don't want a public-use web-app to have any sort of access to your corporate network, much less be able to put auth credentials anywhere near AD.
You seem to provide too much and too extensible to stick to one technological solution
Solution 3.
I would base the whole application around a User class
You would just simply have to model it so that it will provide you with the needed flexibility and extensibility
Something like:
[ClassAttribute ( "Yordan Georgiev", "1.0.2", "20090302", "20090415" , false )]
public class User
{
#region DomainName
private string _DomainName;
public string DomainName
{
get { return _DomainName; }
set { _DomainName = value; }
} //eof property DomainName
#endregion DomainName
#region Status
private int _Status;
public int Status
{
get { return _Status; }
set { _Status = value; }
} //eof property Status
#endregion Status
#region Password
private string _Password = Resources.GV.Pass;
public string Password
{
get { return _Password; }
set {
_Password = GenApp.Utils.Security.Encryptor.Encrypt ( value,
GenApp.Conf.GenAppSettings.Instance.EncryptionAlgorithm );
//debug_Password = value; //unencrypted
}
} //eof property Password
#endregion Password
#region ListUserRoles
private List<UserRole> _ListUserRoles;
public List<UserRole> ListUserRoles { get { return _ListUserRoles; } set { _ListUserRoles = value; } }
#endregion ListUserRoles
#region UserSettings
private GenApp.Conf.UserSettings _UserSettings;
public GenApp.Conf.UserSettings UserSettings
{
get {
if (_UserSettings == null)
_UserSettings = (GenApp.Conf.UserSettings)GenApp.Conf.GenAppSettings.Instance;
return _UserSettings;
}
set { _UserSettings = value; }
} //eof property UserSettings
}
I'm developing a new ASP .NET website which is effectively a subset of the pages in another site we've just released. Two or three of the pages will need minor tweaks but nothing significant.
The obvious answer is to simply copy all of the code and markup files into the new project, make the aforementioned tweaks, and consider the job done. However I'm not keen on this at all due to the amount of duplicated code it will create.
My next idea was to move the code for the pages (i.e. the code-behind file) into a separate assembly which can then be referenced from both sites. This is a little awkward however as if you don't take the designer file with it, you get a lot of build errors relating to missing controls. I don't think moving the designer file is a good idea though as this will need to be regenerated each time the markup is altered.
Does anyone have any suggestions for a clean solution to this problem?
You might want to take a look at the MVP pattern. Since you are probably using WebForms it would be hard to migrate to ASP.Net MVC, but you could implement MVP pretty easily into existing apps.
On a basic level you would move all the business logic into a Presenter class that has a View that represents some sort of interface:
public class SomePresenter
{
public ISomeView View{get; set;}
public void InitializeView()
{
//Setup all the stuff on the view the first time
View.Name = //Load from database
View.Orders = //Load from database
}
public void LoadView()
{
//Handle all the stuff that happens each time the view loads
}
public Int32 AddOrder(Order newOrder)
{
//Code to update orders and then update the view
}
}
You would define your interface to hold the atomic types you want to display:
public interface ISomeView
{
String Name {get; set;}
IList<Order> Orders{get; set;}
}
Once those are defined you can now simply implement the interface in your form:
public partial class SomeConcreteView : System.Web.UI.Page, ISomeView
{
public SomePresenter Presenter{get; set;}
public SomeConcreteView()
{
Presenter = new SomePresenter();
//Use the current page as the view instance
Presenter.View = this;
}
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
{
Presenter.InitializeView();
}
Presenter.LoadView();
}
//Implement your members to bind to actual UI elements
public String Name
{
get{ return lblName.Text; }
set{ lblName.Text = value; }
}
public IList<Order> Orders
{
get{ return (IList<Order>)ordersGrid.DataSource; }
set
{
ordersGrid.DataSource = value;
ordersGrid.DataBind();
}
}
//Respond to UI events and forward them to the presenter
protected virtual void addOrderButton_OnClick(object sender, EventArgs e)
{
Order newOrder = //Get order from UI
Presenter.AddOrder(newOrder);
}
}
As you can see, your code behind is now extremely simple so code duplication is not a big deal. Since the core business logic is all wrapped up in a DLL somewhere, you don't have to worry about functionality getting out of sync. Presenters can be used in multiple views, so you have high reuse, and you are free to change the UI without affecting the business logic as long as you adhere to the contract.
This same pattern can apply to user controls as well, so you can get as modular as you need to. This pattern also opens up the possibility for you to unit test your logic without having to run a browser :)
The patterns and practices group has a nice implementation of this: WCSF
However, you don't have to use their framework to implement this pattern. I know this may look a little daunting at first, but it will solve many of the problems (In my opinion) you are running into.
Create user controls (widgets) or templates to tweak what you want to achieve.
It might also be possible to achieve the same with CSS styles or JavaScript.
Why not create user controls (or custom controls) from the pages which you wish to share? You can then re-use these across both sites.
What we use in our project (JSP, not ASP, but when it comes to building and files it surely isn't an issue?) is to have a base folder of common files, and then another ("instance") folder of additional files and overwrites, and our build script (in ANT, Maven should be fine too) will first copy the base folders, and then based upon a parameter supplied select which instance's files to copy across as well.
Thus we can change a file in the base, and have it apply across all instances.
An issue is that changing a base file will not update any instance file that overwrites it but at least you can make a process for these updates. Presumably you could also use the SVN (etc) revision to flag a build error is an instance file is older than a base file, but we haven't implemented anything that clever yet.
In addition your back-end code (Struts actions in our case) will end up handling all cases rather than any particular instance's cases only. But at least all the code is in one place, and the logic should be clear ("if (instance == FooInstance) { doFooInstanceStuff(...); }").