I'm trying to seed and AppUser with Entity framework database in using the abp.framework (version 3). I know how to seed a IdentityUser using IdentityUserManager but can not find any documentation of how to seed an entity that extends abpUser like appUser. I'm setting the password when I'm seeding (for demo data purposes).
I was able to add users on seed using the following.
This code adds 2 admin users and 1 user with no roles. Add this class to your Domain project in a separate file and when you run the DbMigrator project the users will be created. Note this is a simplified version of what I did and I've cut it down to answer the question, I've not tried it in a live project but everything you need is in there.
using System;
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Identity;
namespace Your.Project
{
class AddUsersDataSeederContributor
: IDataSeedContributor, ITransientDependency
{
private readonly IdentityUserManager _identityUserManager;
public AddUsersDataSeederContributor(IdentityUserManager identityUserManager)
{
_identityUserManager = identityUserManager;
}
public async Task SeedAsync(DataSeedContext context)
{
// Add users
IdentityUser identityUser1 = new IdentityUser(Guid.NewGuid(), "test_user1", "testuser1#email.com");
await _identityUserManager.CreateAsync(identityUser1, "1q2w3E*");
await _identityUserManager.AddToRoleAsync(identityUser1, "Admin");
IdentityUser identityUser2 = new IdentityUser(Guid.NewGuid(), "test_user2", "testuser2#email.com");
await _identityUserManager.CreateAsync(identityUser2, "1q2w3E*");
await _identityUserManager.AddToRoleAsync(identityUser2, "Admin");
IdentityUser identityUser3 = new IdentityUser(Guid.NewGuid(), "test_user3", "testuser3#email.com");
await _identityUserManager.CreateAsync(identityUser3, "1q2w3E*");
//await _identityUserManager.AddToRoleAsync(identityUser3, "Admin"); // Intentionally not making this user and admin
}
}
}
Related
I open one database at the start, then need to open another database based on user selecting two values. The database selection has to be at run-time and will change every time.
Have tried to access the Connection String using the Connection String class and have tried other options like Singleton which I do not understand. I am running this on a local Windows 10 system running SQL Server Express. Am coding using Asp.Net Core 2.1
> ASP.Net Core v2.1
Building multi tenant, multi year application
Every client will have one SQL DATABASE per year
I hope to have a table with the following structure
COMPANY_CODE VARCHAR(3),
COMPANY_YEAR INT,
COMPANY_DBNAME VARCHAR(5)
Sample Data
COMPANY_CODE: AAD
COMPANY_YEAR: 19
COMPANY_DB: AAD19
COMPANY_CODE: AAD
COMPANY_YEAR: 18
COMPANY_DB: AAD18
COMPANY_CODE: AAD
COMPANY_YEAR: 17
COMPANY_DB: AAD17
So, every company will multiple rows - one for each financial year.
The COMPANY_DB column will store the DB name to open for that session.
Once the user is authenticated, I want to change the connection string to point to the database in the COMPANY_DB column of the selected row and then let the logged in user perform transactions.
I am unable to figure out how to change the connection string that is embedded in startup.cs.
Any tips on how to achieve this will be most appreciated.
I figured out that you are using one DbContext class for each database. See here for more information: docs.
Remove AddDbContext from Startup, remove OnConfiguring from DbContext and pass options to the constructor.
public class BloggingContext : DbContext
{
public BloggingContext(DbContextOptions<BloggingContext> options)
: base(options)
{ }
public DbSet<Blog> Blogs { get; set; }
}
Then, write service providing DbContext:
public interface IBlogContextProvider
{
BlogContext GetBlogContext(string connectionString);
}
public class BlogContextProvider : IBlogContextProvider
{
BlogContext GetBlogContext(string connectionString)
{
var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseSqlServer(connectionString);
return new BlogContext(optionsBuilder);
}
}
Add service in your Startup.cs:
services.AddScoped<IBlogContextProvider, BlogContextProvider>();
Now you can use DI:
public class HomeController : Controller
{
private IBlogContextProvider _provider;
public HomeController(IBlogContextProvider provider)
{
_provider = provider;
}
public ActionResult Index()
{
using (var context = _provider.GetBlogContext(<your connection string>))
{
//your code here
}
return View();
}
}
EDIT: Of course, you can write ContextProvider as generic.
Been looking into the identity server 4 solution to compliment my ASP CORE api.
Using a SPA page on front end, does IdentityServer4 have the capability to manage restfull calls for login/logout/other?
Currently my solution works perfectly to redirect to and from the IdentityServer4 solution, but wondering if i can improve on UX by avoiding the redirects that occur on login/logout?
I've heard of PopUp and iFrame capability, but from research that opens up other risks.
(not sure if this question is for stackoverflow or software engineering stack, happy to move it)
You may do this by using the resource owner password grant type, where you could provide your own login screen and pass the information to IdentityServer.
In IdentityServer you would implement the IResourceOwnerPasswordValidator interface to validate the users.
In your Startup.ConfigureServices add the following.
Services.AddTransient<IResourceOwnerPasswordValidator, ResourceOwnerPasswordValidator>();
Here is a sample ResourceOwnerPasswordValidator class.
public class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{
private IUserManager _myUserManager { get; set; }
public ResourceOwnerPasswordValidator(IUserManager userManager)
{
_myUserManager = userManager;
}
public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
{
var user = await _myUserManager.Find(context.UserName, context.Password);
if (user != null)
{
context.Result = new GrantValidationResult(
subject: user.USER_ID,
authenticationMethod: "custom",
claims: await _myUserManager.GetClaimsAsync(user));
}
else
{
context.Result = new GrantValidationResult(
TokenRequestErrors.InvalidRequest,
errorDescription: "UserName or Password Incorrect.");
}
}
}
The IUserManager implements the logic to check the database to validate the user.
Then the SPA client would use the GrantTypes.ResourceOwnerPassword. Here is an example you could start with.
DISCLAIMER
This is not the recommended flow to use.
I tried authenticating with Google Admin Api-sdk But We get some file missings error which should be created by the Dlls, we are using.
Even after adding all the recommended dlls after going through many article for the same, I din get over to this. Here is the code im using.
protected void Page_Load(object sender, EventArgs e)
{
const string serviceAccountEmail = "<id>#developer.gserviceaccount.com";
const string serviceAccountCertPath = #"E:\Test.p12";
const string serviceAccountCertPassword = "notasecret";
const string userEmail = "admin#mydomain.com";
var certificate = new X509Certificate2(serviceAccountCertPath, serviceAccountCertPassword, X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[] { DirectoryService.Scope.AdminDirectoryUser },
User = userEmail
}.FromCertificate(certificate));
var service = new DirectoryService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "User Provisioning",
});
User newuserbody = new User();
UserName newusername = new UserName();
newuserbody.PrimaryEmail = "Harsh#test.com";
newusername.GivenName = "Harsh";
newusername.FamilyName = "Sharma";
newuserbody.Name = newusername;
newuserbody.Password = "test#123";
User results = service.Users.Insert(newuserbody).Execute();
}
}
}
I am using this code for new user provisioning but Google.Apis.Admin.Directory.directory_v1.cs not found while debugging due to this authentication got failed. Please anybody let me know to to get Google.Apis.Admin.Directory.directory_v1.cs file. As much i know i have already added all the dlls added.
The Namespaces i am using are as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Util.Store;
using Google.Apis.Admin.Directory.directory_v1;
using Google.Apis.Admin.Directory.directory_v1.Data;
using DotNetOpenAuth.GoogleOAuth2;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using Google.Apis.Auth.OAuth2.Requests;
using Google.Apis.Auth.OAuth2.Responses;
As per the documentation, you need to download an extra NuGet package for each API you want to use. These packages contain the generated code for that particular API.
thanks all for replying,
I managed to run it successfully, I had all the reference, Code was upto the mark as well.
The Only problem was with the admin setting there in the google admin panel.
I manage to correct them as per my request to google API's and it worked fine.
In my Profile class I have
#OneToOne(cascade=CascadeType.PERSIST)
private ProfilePicture profilePic = null;
My method in updating the profilePic
public Profile updateUserProfilePic(Profile user) {
EntityManager em = EMF.get().createEntityManager();
em.getTransaction().begin();
Profile userx = em.find(Profile.class, user.getEmailAddress());
userx.setProfilePic( user.getProfilePic() );
em.getTransaction().commit();
em.close();
return userx;
}
When updateUserProfilePic is called, it just add another profilePic in datastore, it doesn't replaced the existing profilePic. Is my implementation correct? I want to update the profilePic of profile.
"Transient" means not persistent and not detached.
Using that version of GAE JPA you need a detached or managed object there if you want it to reuse the existing object.
Using v2 of Googles plugin there is a persistence property that allows merge of a transient object that has "id" fields set.
My question is similar to this question. I hope I can provide some more detail and context to get it answered.
So here's some context: I have a simple in-house silverlight (ver 4) app with WCF Ria services that I'm building for our small support team. It uses authentication against a third-party vended database, but all other user information, e.g. FriendlyName and Roles (only 1 role per user) comes from our own database. I'm trying to keep this simple and don't want to implement custom membership and role providers.
I have few domain service operations that I want to restrict to certain roles, so I tried using the RequiresRole attribute like so:
[RequiresRole("Admin", "HelpDesk", "Billing" )]
public RisStudyInfo GetStudyInfo(string accession) {
return ris.GetStudyInfo(accession);
}
On the client side WebContext.Current.User.IsInRole("Admin") returns true, but I always get access denied when calling the service. The RequiresAuthentication attribute works as expected.
Below is the implementation of my AuthenticationService. The User class simply inherits from UserBase and adds the FriendlyName property. Any ideas what I'm doing wrong?
[EnableClientAccess]
public class AuthenticationService : AuthenticationBase<User> {
UserDataService userData = new UserDataService();
protected override bool ValidateUser(string userName, string password) {
var auth = new DatabaseAuthenticator();
return auth.Authenticate(userName, password);
}
protected override User GetAuthenticatedUser(IPrincipal principal) {
User user = null;
if (principal.Identity.IsAuthenticated) {
user = new User();
user.FriendlyName = userData.GetFriendlyName(principal.Identity.Name);
user.Name = principal.Identity.Name;
user.Roles = GetRolesFor(user.Name);
}
return user;
}
private IEnumerable<string> GetRolesFor(string username) {
IList<string> roles = new List<string>();
string role = userData.GetRolesFor(username);
if (role != null)
roles.Add(role);
return roles;
}
Figured it out. At least 2 things wrong. First clue found here. The second clue here
1.Turns out I really do need to write a custom role provider. Only need to implement GetRolesForUser though.
public override string[] GetRolesForUser(string username) {
return new string[] { _userService.GetRolesFor(username) };
}
2.Configure the custom role provider correctly in the web.config
<roleManager cacheRolesInCookie="true" enabled="true" defaultProvider="MyRoleProvider">
<providers>
<add name="MyRoleProvider" type="MyProject.Web.Providers.MyRoleProvider, MyProject.Web"/>
</providers>
</roleManager>
I solved this one by using the local credential store to cache credentials. Whenever a local cred check fails a foreign check occurs and the cache is populated/updated. This was a trivial override of the ValidateUser method. It does mean that stale passwords continue to work until the updated password is used (it will fail locally, pass remotely and trigger an update).
This approach meant that internally everything worked as per an out of the box configuration with no need for any other mods (apart from removing the local create-a-user links).