Adding database to Spring Security and Angular JS - angularjs

So i followed this tutorial https://spring.io/guides/tutorials/spring-security-and-angular-js/
But i have trouble figuring out how to add the database.
I have added this to the properties files so i have connection to the database
spring.datasource.url=jdbc:mysql://localhost:3306/login
spring.datasource.username=root
spring.datasource.password=root
in sql i create a table as follow
CREATE TABLE IF NOT EXISTS `login`.`users` (
`idusers` INT NOT NULL AUTO_INCREMENT COMMENT '',
`username` VARCHAR(45) NULL COMMENT '',
`password` VARCHAR(256) NULL COMMENT '',
`authority` VARCHAR(45) NULL COMMENT '',
PRIMARY KEY (`idusers`) COMMENT '')
ENGINE = InnoDB;
and added some users.
I want this to replace this with the database.
#Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
.and()
.withUser("admin").password("admin").roles("USER", "ADMIN", "READER", "WRITER")
.and()
.withUser("audit").password("audit").roles("USER", "ADMIN", "READER");
}
And something i'm confused of is of that i still need the Principal user when using my own database.
#RequestMapping("/user")
public Principal user(Principal user) {
System.out.println(user.getName());
System.out.println(user.toString());
return user;
}

Take a look to the documentation (http://docs.spring.io/spring-security/site/docs/4.0.2.RELEASE/reference/htmlsingle/#jc-authentication-jdbc)
and see how you'll need to change your globalUserDetails method to use a jdbcAuthentication instead of an inMemoryAuthentication :
#Autowired
private DataSource dataSource;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource(dataSource)
.withDefaultSchema()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
The actual configuration is suited for in memory database as it creates a new schema upon initialisation. In your case you should change it to something like :
#Autowired
private DataSource dataSource;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery(/* set a query to suit your model*/)
.authoritiesByUsernameQuery(/* set a query to suit your model*/)
.groupAuthoritiesByUsername(/* set a query to suit your model*/);
}
Principal is just an interface that gives you access to the currently logged in user, no more no less.
More on Spring MVC + Security here : http://docs.spring.io/spring-security/site/docs/4.0.2.RELEASE/reference/htmlsingle/#mvc
http://docs.spring.io/spring-security/site/docs/4.0.2.RELEASE/reference/htmlsingle/#mvc-authentication-principal

Related

I can't load a ready database in my room database although I put it in Assets folder

Room.databaseBuilder(getApplicationContext(), UserDatabase.class,"users_db")
.createFromAsset("users.db")
.build();
UserDatabase db = Room.databaseBuilder(getApplicationContext(),
UserDatabase.class,"users_db").allowMainThreadQueries()
.fallbackToDestructiveMigration()
.addMigrations()
.build();
Even I tried to add as a file to prepopulate as "createFromFile" with the following code
Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
.createFromFile(new File("mypath"))
.build();
If the above is the only code then unless you try to access the database, the database will not be created. That is just getting an instance of the built database just creates an instance that is ready to open the database.
So if you have, for example :-
UserDatabase db = Room.databaseBuilder(getApplicationContext(),
UserDatabase.class,"users_db").allowMainThreadQueries()
.createFromAsset("users.db")
.build();
Then it is not until, for example, you did
SupportSQLiteDatabase accessedDatabase = db.getOpenHelper().getWritableDatabase();
That an attempt to open the database (in the case of no database existing, then an attempt to create the database, and in the case of createFromAsset the create database will then attempt the copy from the asset).
Typically you would not get a SupportSQliteDatabase but would simply try to access the database via the Dao's ( i.e. the methods in the interfaces or abstract classes that are annotated with #Dao).
Demonstration
Consider the following :-
An existing database from an external source (Navicat in the example) :-
just a single table and therefore #Entity annotated class will be required.
as can be seen it has 3 users.
IMPORTANT the schema MUST adhere to what Room expects, which has limitations
The database is copied to the assets folder as users.db :-
An #Entity annotated class User (so the table name will be User) :-
#Entity
class User {
#PrimaryKey
Long id = null;
String username;
}
2 columns
id which is the Primary Key and as the type is Long then the column type must be INTEGER
username, as it's a String then column type MUST be TEXT, as there is no #NonNUll annotation then NOT NULL should not be coded (if it were then the schema room expects would not be as above)
An #Dao annotated class UserDao :-
#Dao
interface UserDao {
#Insert
long insert(User user);
#Query("SELECT * FROM user")
List<User> getAllUsers();
}
An #Database annotated class UserDatabase :-
#Database(entities = {User.class}, version = 1,exportSchema = false)
abstract class UserDatabase extends RoomDatabase {
abstract UserDao getUserDao();
private static volatile UserDatabase instance = null;
static UserDatabase getInstance(Context context) {
if (instance == null) {
instance = Room.databaseBuilder(context,UserDatabase.class,"users_db")
.allowMainThreadQueries()
.createFromAsset("users.db")
.build();
}
return instance;
}
}
note the getInstance() method (see the activity code that follows)
Putting it all together in an activity
First a shortened version that does not access the database but just gets an instance of the UserDatabase :-
public class MainActivity extends AppCompatActivity {
UserDatabase db;
UserDao dao;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
db = Room.databaseBuilder(this,UserDatabase.class,"users_db")
.allowMainThreadQueries()
.createFromAsset("users.db")
.build();
dao = db.getUserDao(); //<<<<< WILL NOT OPEN THE DATABASE
}
}
When the above is run AppInspection shows nothing.
However, using :-
public class MainActivity extends AppCompatActivity {
UserDatabase db;
UserDao dao;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
db = Room.databaseBuilder(this,UserDatabase.class,"users_db")
.allowMainThreadQueries()
.createFromAsset("users.db")
.build();
dao = db.getUserDao(); //<<<<< WILL NOT OPEN THE DATABASE
//db.getOpenHelper().getWritableDatabase(); //<<<<< Force an open of the database
//<<<<< WILl OPEN THE DATABASE
for(User u: dao.getAllUsers()) {
Log.d("USERINFO","UserName is" + u.username + " ID is " + u.id);
}
}
/*
Example of using the singleton (not called)
*/
void unusedFromExample() {
UserDatabase db = UserDatabase.getInstance(this);
UserDao dao = db.getUserDao();
/// etc
}
}
and the log includes (as expected) :-
D/USERINFO: UserName isuser1 ID is 1
D/USERINFO: UserName isuser2 ID is 2
D/USERINFO: UserName isuser3 ID is 2000
And AppInspection shows the database and that it has ben copied.

Specify a schema using r2dbc-mssql

Is there any way to specify a default schema in a properties file using r2dbc-mssql?
The connection works fine with:
spring:
r2dbc:
url: 'r2dbc:mssql://zzzzz.database.windows.net:1433/dbname'
username: 'xxxxxx'
password: 'xxxxxx'
but i have to use a static schema:
#Table("schemaname.foo")
public class Foo {
#Id
private Long id;
I've found something similar in r2dbc-postgresql:
https://github.com/pgjdbc/r2dbc-postgresql/issues/37
In a Spring Boot application, I think you can execute a sql statement to switch schemas in the #PostConstruct method of a #Configuration class.
#Configuration
class DatabaseConfig{
#Autowired
ConnectionFactory connectionFactory;
#PostConstruct
void init(){
Mono.from(connectionFactory.getConnection())
.flatMap(c->c.createStatement("switch to your schema here, different database has different commands here").execute())
.subscribe()
}
}

Spring Batch "Invalid object name BATCH_JOB_INSTANCE"

I've created a spring batch to query a Azure SQL server database and write the data into a CSV file. I do not have create permissions for the database. I get this error Invalid Object name BATCH_JOB_INSTANCE on running the batch. I don't want the spring batch meta-data tables to be created in the main database. Or it would be helpful if I can have them in another local or in-memory db like h2db.
I've also added spring-batch-initialize-schema=never already, which was the case with most answers to similar questions on here, but that didn't help.
Edit:
I resolved the Invalid Object name error by preventing the metadata tables from being created into the main database by extending the DefaultBatchConfigurer Class and Overriding the setDataSource method, thus having them created in the in-memory map-repository. Now I want to try two options:
How to have the meta data tables to be created in a local db or in-memory db like h2db.
Or If I have the meta data tables created already in the main database, in a different schema than my main table I'm fetching from. How to point my job to those meta-data tables in another schema, to store the job and step details data in those.
#Configuration
public class SpringBatchConfig extends DefaultBatchConfigurer{
#Override
public void setDataSource(DataSource datasource) {
}
...
My application.properties file looks like this:
spring.datasource.url=
spring.datasource.username=
spring.datasource.password=
spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring-batch-initialize-schema=never
spring.batch.job.enabled=false
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect
I've created a demo with two datasources. Batch metadata will sotre in H2 DB and the Job datasource is Azure SQL.
Here is the project structure:
We need define a DataSourceConfig class and use #Primary annotation for DataSource bean:
#Configuration
public class DataSourceConfig {
#Bean(name = "mssqlDataSource")
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource appDataSource(){
return DataSourceBuilder.create().build();
}
#Bean(name = "h2DataSource")
#Primary
// #ConfigurationProperties(prefix="spring.datasource.h2")
public DataSource h2DataSource() {
return DataSourceBuilder.create()
.url("jdbc:h2:mem:thing:H2;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE")
.driverClassName("org.h2.Driver")
.username("sa")
.password("")
.build();
}
}
In the ItemReaderDbDemo class, we use #Autowired #Qualifier("mssqlDataSource") to specify the dataSource in the Spring Batch task:
#Configuration
public class ItemReaderDbDemo {
//generate task Object
#Autowired
private JobBuilderFactory jobBuilderFactory;
//Step exec tasks
//generate step Object
#Autowired
private StepBuilderFactory stepBuilderFactory;
#Autowired
#Qualifier("mssqlDataSource")
private DataSource dataSource;
#Autowired
#Qualifier("dbJdbcWriter")
private ItemWriter<? super Todo> dbJdbcWriter;
#Bean
public Job itemReaderDbDemoJob() {
return jobBuilderFactory.get("itemReaderDbDemoJob").start(itemReaderDbStep()).build();
}
#Bean
public Step itemReaderDbStep() {
return stepBuilderFactory.get("itemReaderDbStep")
.<Todo,Todo>chunk(2)
.reader(dbJdbcReader())
.writer(dbJdbcWriter)
.build();
}
#Bean
#StepScope
public JdbcPagingItemReader<Todo> dbJdbcReader() {
JdbcPagingItemReader<Todo> reader = new JdbcPagingItemReader<Todo>();
reader.setDataSource(dataSource);
reader.setFetchSize(2);
reader.setRowMapper(new RowMapper<Todo>() {
#Override
public Todo mapRow(ResultSet rs, int rowNum) throws SQLException {
Todo todo = new Todo();
todo.setId(rs.getLong(1));
todo.setDescription(rs.getString(2));
todo.setDetails(rs.getString(3));
return todo;
}
});
SqlServerPagingQueryProvider provider = new SqlServerPagingQueryProvider();
provider.setSelectClause("id,description,details");
provider.setFromClause("from dbo.todo");
//sort
Map<String,Order> sort = new HashMap<>(1);
sort.put("id", Order.DESCENDING);
provider.setSortKeys(sort);
reader.setQueryProvider(provider);
return reader;
}
}
Here is my application.properties:
logging.level.org.springframework.jdbc.core=DEBUG
spring.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.jdbcUrl=jdbc:sqlserver://josephserver2.database.windows.net:1433;database=<Your-Database-Name>;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;
spring.datasource.username=<Your-UserName>
spring.datasource.password=<Your-Password>
spring.datasource.initialization-mode=always
It return expected result from my Azure SQL. By the way, my Azure sql username does not have create permissions for the database.
The result shows:
How to have the meta data tables to be created in a local db or in-memory db like h2db.
You can use spring.batch.initialize-schema=embedded for that.
Or If I have the meta data tables created already in the main database, in a different schema than my main table I'm fetching from. How to point my job to those meta-data tables in another schema, to store the job and step details data in those.
spring batch works against a datasource, not a particular schema. If meta-data tables are in a different schema, then you need to create a second datasource pointing to that schema and set it on the job repository.
I know this post is a little bit old, but I'd like to give an update.
For newer versions of Spring Boot spring.batch.initialize-schema is deprecated.
I'm using Spring Boot 2.7.1 and the newer property is spring.batch.jdbc.initialize-schema.
In my case: when I was receiving the error message was due that the user did not have the CREATE TABLE permission to create the corresponding spring bacth tables.
Adding the permissions fix the issue.

Change SQL Server Connection String Dynamically inside an ASP.Net Core application

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.

Using SQL Server 2008 Schema with JPA

I got a MS SQL Server (2008) database with two schemas, dbo as default for general purpose e.g. authentication and myapp for domain objects. I want to have JPA-Entitys in both Schemas. I use SpringBoot for configuration.
Entitys tables are created in the right schema as they should, e.g. myschema.job, but relationship tables, e.g. Job_Employee are created within the default schema dbo. How can I set in whicht schema automatically created tables are stored (without changing the default schema as this just shifts the problem)?
#Entity
#Table(schema="myschema")
public class Job {[...]
My application.yml looks like:
spring:
profiles: dev
datasource:
datasource1:
url: jdbc:sqlserver://localhost;databaseName=mydb;schema=myschema
username: SA
password: ###
datasource2:
url: jdbc:sqlserver://localhost;databaseName=mydb;schema=dbo
username: SA
password: ###
jpa:
show-sql: true
hibernate.ddl-auto : create-drop
properties:
hibernate.dialect: org.hibernate.dialect.SQLServer2012Dialect
hibernate.default_schema: dbo
And the datasources are Configured in
#Configuration
#EnableJpaRepositories
public class JPAConfiguration {
#Bean
#Primary
#ConfigurationProperties("spring.datasource.datasource1")
public DataSourceProperties firstDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#Primary
#ConfigurationProperties("spring.datasource.datasource1")
public DataSource firstDataSource() {
return firstDataSourceProperties().initializeDataSourceBuilder().build();
}
#Bean
#ConfigurationProperties("spring.datasource.datasource2")
public DataSourceProperties secondDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#ConfigurationProperties("spring.datasource.datasource2")
public DataSource secondDataSource() {
return secondDataSourceProperties().initializeDataSourceBuilder().build();
}
}
Thanks!
The answer is: every Collection must be mapped to the right schema as well with #JoinTable annotation.
E.g. in our Case:
#JoinTable(schema="myschema")
#OneToMany(cascade=CascadeType.ALL)
#Column(nullable = false)
private List<Employee> employee;
This results in a table calles myschema.job_employee.

Resources