你可以試著將〈套用 jdbcAuthentication〉中的 gossip 專案,遷移至 Spring Boot,這可以簡化一些設定,後續要加上一些功能時,也會方便一些。
需要的 Starter 有 AOP、JDBC、Mail、Security、Web、Thymeleaf、H2,另外,你還需要 OWASP Java Html Sanitizer、Thymeleaf 模版的 Security 方言,也就是最後 build.gradle 中會有以下設定:
...略
dependencies {
implementation('org.springframework.boot:spring-boot-starter-aop')
implementation('org.springframework.boot:spring-boot-starter-jdbc')
implementation('org.springframework.boot:spring-boot-starter-mail')
implementation('org.springframework.boot:spring-boot-starter-security')
implementation('org.springframework.boot:spring-boot-starter-thymeleaf')
implementation('org.springframework.boot:spring-boot-starter-web')
implementation('com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20171016.1')
runtimeOnly('com.h2database:h2')
runtimeOnly('org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.0.4.RELEASE')
testImplementation('org.springframework.boot:spring-boot-starter-test')
testImplementation('org.springframework.security:spring-security-test')
}
為了簡化設定,你可以將一些 .properties 的設定,直接放到 application.properties 之中:
spring.thymeleaf.cache=false
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:tcp://localhost/c:/workspace/gossip/gossip
spring.datasource.username=caterpillar
spring.datasource.password=12345678
path.url.member=/member
path.url.index=/
path.view.register_success=register_success
path.view.register_form=register
path.view.verify=verify
path.view.forgot=forgot
path.view.reset_password_form=reset_password
path.view.reset_password_success=reset_success
path.view.index=index
path.view.user=user
path.view.member=member
mail.user=yourname@gmail.com
mail.password=yourpassword
然後將專案中的靜態資源放到 static 資料夾,模版檔案放到 templates 資料夾,將 gossip.mv.db 放到專案根目錄。
原始碼的部份,將 cc.openhome.aspect
、cc.openhome.controller
與 cc.openhome.model
套件中類別原始碼複製至專案。
為了簡化,暫且只使用一個 JavaConfig,也就是建立專案時標註了 @SpringBootApplication
的設定檔之中:
package cc.openhome.gossip;
...略
@SpringBootApplication(
scanBasePackages={
"cc.openhome.controller",
"cc.openhome.model",
"cc.openhome.aspect"
}
)
public class GossipApplication {
public static void main(String[] args) {
SpringApplication.run(GossipApplication.class, args);
}
@Autowired
private DataSource dataSource;
@Autowired
private PasswordEncoder passwordEncoder;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public WebSecurityConfigurerAdapter webSecurityConfig() {
return new WebSecurityConfigurerAdapter() {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/member", "/new_message", "/del_message", "/logout").hasRole("MEMBER")
.anyRequest().permitAll()
.and()
.formLogin().loginPage("/").loginProcessingUrl("/login")
.successHandler((request, response, auth) -> {
response.sendRedirect("/member");
})
.failureHandler((request, response, ex) -> {
response.sendRedirect("/?username=" + request.getParameter("username") + "&error");
})
.and()
.logout().logoutUrl("/logout")
.addLogoutHandler((request, response, auth) -> {
request.getSession().invalidate();
try {
response.sendRedirect("/");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
})
.and()
.csrf().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.passwordEncoder(passwordEncoder)
.dataSource(dataSource)
.usersByUsernameQuery("select name, password, enabled from t_account where name=?")
.authoritiesByUsernameQuery("select name, role from t_account_role where name=?");
}
};
}
@Bean
public PolicyFactory htmlPolicy() {
return new HtmlPolicyBuilder()
.allowElements("a", "b", "i", "del", "pre", "code")
.allowUrlProtocols("http", "https")
.allowAttributes("href").onElements("a")
.requireRelNofollowOnLinks()
.toFactory();
}
}
如此一來,就完成了專案遷移,你可以在 gossip 中找到以上的範例專案。