Hur navigerar man runt med Spring REST API på ett snyggt sätt?
Denna fråga är till perfektionister. Jag har idag för första gången satt mig ned och börjat programmera med lite Spring och jag måste säga att jag uppskattar verkligen @Bean och @AutoWiring annoteringarna. Livet blev så mycket lättare med "Goto"-java kan man enkelt uttryligt säga.
Jag har märkt att det verkar finnas flera olika sätt hur att naigera runt med en REST API i Spring och nu vänder jag mig till er duktiga som vet den goda praktiken.
Låt oss säga att jag har skapat denna SpringSecurity konfigurationen. Denna kod säger att vi använder oss av JDBC databas, vi sätter rättigheter beroende på om man är ADMIN eller USER. Sedan har vi skapat ett objekt som krypterar lösenord. Detta objekt ska vi återanvända då jag har satt @Bean på den som annotering.
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
@Autowired
private DataSource dataSource;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource)
.passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic()
.and()
.authorizeRequests()
// Normal users
.antMatchers(HttpMethod.GET, "/user/**").hasRole("USER")
// Administrator
.antMatchers(HttpMethod.GET, "/user/**").hasRole("ADMIN")
.antMatchers(HttpMethod.POST, "/user/**").hasRole("ADMIN")
.antMatchers(HttpMethod.PUT, "/user/**").hasRole("ADMIN")
.antMatchers(HttpMethod.PATCH, "/user/**").hasRole("ADMIN")
.antMatchers(HttpMethod.DELETE, "/user/**").hasRole("ADMIN")
.and()
.csrf().disable()
.formLogin().disable();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Där efter har jag skapat lite databas också till mig. Enkelt att förstå denna kod. Här skapar jag alltså en datakälla vid namn dataSource och jag skapar även två tabeller.
@Configuration
@EnableTransactionManagement
public class HibernateConfig {
private static final String USERNAME = "admin";
private static final String PASSWORD = "password";
private static final String DRIVER = "com.mysql.cj.jdbc.Driver";
private static final String ADDRESS = "jdbc:mysql://localhost:3306";
private static final String DATABASE = "MyDatabase";
private DriverManagerDataSource dataSource;
@Bean
public DataSource dataSource() {
dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(DRIVER);
dataSource.setUsername(USERNAME);
dataSource.setPassword(PASSWORD);
dataSource.setUrl(ADDRESS + "/" + DATABASE + "?createDatabaseIfNotExist=true");
return dataSource;
}
@Bean
public JdbcTemplate createTables() {
// The standard JDBC implementation of the UserDetailsService
String userTableQuery = "create table users(username varchar_ignorecase(50) not null primary key,password varchar_ignorecase(50) not null,enabled boolean not null)";
String authoritiesTableQuery = "create table authorities (username varchar_ignorecase(50) not null,authority varchar_ignorecase(50) not null,constraint fk_authorities_users foreign key(username) references users(username))";
String index = "create unique index ix_auth_username on authorities (username,authority)";
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.execute(userTableQuery);
jdbcTemplate.execute(authoritiesTableQuery);
jdbcTemplate.execute(index);
return jdbcTemplate;
}
}
Dessa funktioner ovan anropas när Spring Boot startas upp. Åter igen så kommer mina @Beans till nytta.
SpringBootApplication
public class JWiFiLoggerServerApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(JWiFiLoggerServerApplication.class, args);
// First create a database if not created
context.getBean(HibernateConfig.class).dataSource();
// Then create the tables if they are not created
context.getBean(HibernateConfig.class).createTables();
}
}
Och nu till min fråga. Som du ser ovan så har jag satt olika begränsningar på vem som får gå vart...eller rättare sakt, vem som får skicka data eller hämta data. Denna kod har jag rakt kopierat av utan att direkt förstå något om allt är nödvändigt eller inte. Jag har förståelse vad alla .antMatchers() gör.
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic()
.and()
.authorizeRequests()
// Normal users
.antMatchers(HttpMethod.GET, "/user/**").hasRole("USER")
// Administrator
.antMatchers(HttpMethod.GET, "/user/**").hasRole("ADMIN")
.antMatchers(HttpMethod.POST, "/user/**").hasRole("ADMIN")
.antMatchers(HttpMethod.PUT, "/user/**").hasRole("ADMIN")
.antMatchers(HttpMethod.PATCH, "/user/**").hasRole("ADMIN")
.antMatchers(HttpMethod.DELETE, "/user/**").hasRole("ADMIN")
.and()
.csrf().disable()
.formLogin().disable();
}
Fråga:
Men om jag vill naviera runt i min REST API, dvs anropa och hämta data i form av respons. Då använder jag mig av följande. Finns det något annat sätt att göra för att få det ännu bättre? Jag tänkte mest på HttpMethod.X konstanterna som jag använder som argument. Behövs dom?
Hur hade du gjort? Mitt mål till att börja med är att jag ska kunna skicka ett helt Java-objekt via internet, från server till klient, eller tvärt om.
@RestController
@RequestMapping("login")
public class LoginController {
@Autowired
private PasswordEncoder passwordEncoder;
@RequestMapping("login/{userName}/{password}")
public void login(@PathVariable("userName") String userName, @PathVariable("password") String password) {
}
}