在Spring Security&Thymeleaf中进行认证和授权
Spring Security 是什么
Spring Security是一个由Spring构建的框架,为应用程序提供身份验证和授权功能。只需添加一些配置,就可以使Web应用程序具有以下功能。
-
- 脆弱性対策
セッションフィクセイション対策
クリックジャッキング対策
CSRF対策
認証・認可
フォーム認証などを用いたログイン機構
ロールを用いたアクセス制御
前提 tí) – prerequisite / premise / condition
這次要做的事
这次我们将使用Spring Security的功能来实现以下内容。
-
- 認証
ユーザとパスワードを使ってフォーム認証する
(データベースでもできるが)インメモリに持たせたユーザとパスワードを使う
ユーザまたはパスワードが違っていたらエラーメッセージを返す
認可
管理者用アカウントと一般ユーザ用でロールを分ける
管理者は /admin と /user にアクセス可能
一般ユーザは /user のみにアクセス可能
请注意,以下将介绍启用 Spring Boot 应用程序安全的步骤。
图书馆的版本
请注意,使用Spring Boot 1.4系列和Spring Security 4.x系列。如果版本不同,则语法完全不同。
示例代码
我们在GitHub上发布了实际运行的示例代码。如果你想要通过阅读代码来理解,可以直接访问下方链接。
- https://github.com/gushernobindsme/spring-security-sample
前備份工作
添加依赖库
本次我们将使用Spring Boot构建服务器端,并使用Tymeleaf作为模板引擎进行页面绘制。为此,您需要以下库。
-
- spring-boot-starter-web
- spring-boot-starter-thymeleaf
为了启用Spring Security的功能,需要以下库。
-
- spring-boot-starter-security
-
- spring-security-web
- spring-security-config
本次为了将Spring Security与Tymeleaf进行集成,我们需要添加以下库。
- thymeleaf-extras-springsecurity4
总结起来,build.gradle 文件将会添加如下配置。
dependencies {
compile("org.springframework.boot:spring-boot-starter-web:1.4.1.RELEASE")
compile("org.springframework.boot:spring-boot-starter-thymeleaf:1.4.1.RELEASE")
compile("org.springframework.boot:spring-boot-starter-security:1.4.1.RELEASE")
compile("org.thymeleaf.extras:thymeleaf-extras-springsecurity4:2.1.3.RELEASE")
compile("org.springframework.security:spring-security-core:4.2.3.RELEASE")
compile("org.springframework.security:spring-security-web:4.2.3.RELEASE")
compile("org.springframework.security:spring-security-config:4.2.3.RELEASE")
}
控制器
首先,我们将创建一个用于管理员的界面和一个用于一般用户的界面。
其中,管理员界面将命名为AdminController,而一般用户界面将命名为UserController。
@Controller
@RequestMapping("/admin")
@Slf4j
public class AdminController {
@RequestMapping
public String index() {
return "admin";
}
}
@Controller
@RequestMapping("/user")
@Slf4j
public class UserController {
@RequestMapping
public String index() {
return "user";
}
}
模板
我們將為相應的Controller準備Tymeleaf模板。分別為admin.html和user.html(詳情請參考示例代碼)。
除此之外,按照 SpringBoot 的习惯创建 Application.java 文件,只要 gradle bootRun 能够通过,准备工作就完成了。
实施示例
由于做好了事前准备,我们现在转到Spring Security的讨论。
设置
首先,我们需要创建一个配置类来启用Spring Security。通过继承WebSecurityConfigurerAdapter并添加@EnableWebSecurity注解,我们就可以使Spring Security生效。
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private static String ROLE_USER = "USER";
private static String ROLE_ADMIN = "ADMIN";
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/user").hasAnyRole(ROLE_USER, ROLE_ADMIN)
.antMatchers("/admin").hasRole(ROLE_ADMIN)
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/user")
.usernameParameter("username")
.passwordParameter("password")
.permitAll()
.and()
.logout()
.permitAll()
.and()
.csrf();
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/*.html", "/*.css")
.antMatchers("/bootstrap/**");
}
}
对于上述例子,大致解释的是
#configure(HttpSecurity)
アクセス制御を有効にする
/user は一般ユーザと管理者ユーザのロールでアクセス可能とする
/admin は管理者ユーザのみアクセス可能とする
フォームログインを有効にする
ログインページの URL は /login とする
ユーザ名は username パスワードは password というプロパティ名とする
ログインに成功した場合は /user に遷移させる
ログインページに対しては、例外的にアクセス制御を無効にする
ログアウトページに対しては、例外的にアクセス制御を無効にする
CSRF 用のトークンを有効にする
#configure(WebSecurity)
デフォルト設定だと静的ファイルに対してもアクセス制御がかかってしまうため、以下については除外する
html
css
BootStrap テンプレートのファイル
差不多就是这样。我想你应该能够想象出设定的实施方式。
为了将Tymeleaf与SpringTemplateEngine配合使用,我们需要为TemplateResolver的实例设置SpringTemplateEngine。具体的实现如下所示。
@Autowired
public TemplateResolver templateResolver;
@Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.addDialect(new SpringSecurityDialect());
engine.setTemplateResolver(templateResolver);
return engine;
}
此外,还需要设置用于身份验证的用户名和密码信息。为了简化实现,本次设置将使用内存而非数据库。有关 UserDto 的示例代码,请参阅文档。
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
UserDto support = supportUser();
UserDto admin = adminUser();
auth.inMemoryAuthentication()
.withUser(support.getUsername()).password(support.getPassword()).roles(ROLE_USER)
.and()
.withUser(admin.getUsername()).password(admin.getPassword()).roles(ROLE_ADMIN);
}
@Bean
@ConfigurationProperties("inmotion.admin")
public UserDto adminUser() {
return new UserDto();
}
@Bean
@ConfigurationProperties("inmotion.user")
public UserDto supportUser() {
return new UserDto();
}
我们决定将实际的用户名称和密码存储在 application.yml 中。
inmotion:
user:
username: user
password: pass12345
admin:
username: admin
password: pass12345
控制器
然后,准备与登录界面相对应的控制器。
@Controller
public class AuthenticationController {
@RequestMapping({"/", "/login"})
public String login(@RequestParam(value = "error", required = false) String error, Model model) {
if (error != null) {
// エラーメッセージを出力する処理
}
return "login";
}
}
模板
只需准备一个登录表单来进行/login的POST即可。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<body>
<div class="container">
<form class="form-signin" method="post" th:action="@{/login}">
<div class="alert alert-dismissible alert-danger" th:if="${errorMessage}">
<button type="button" class="close" data-dismiss="alert">×</button>
<p th:text="${errorMessage}"></p>
</div>
<h2 class="form-signin-heading">Please sign in</h2>
<label for="username" class="sr-only">Username</label>
<input type="text" id="username" name="username" class="form-control" placeholder="UserName"/>
<label for="password" class="sr-only">Password</label>
<input type="password" id="password" name="password" class="form-control" placeholder="Password"/>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</form>
</div>
</body>
</html>
使用Gradle bootRun命令启动应用程序
-
- 指定したユーザ名、パスワードでログインできること
-
- アクセス制御が有効になっていること
認可していない画面にアクセスしようとすると 403 が返ること
CSRF対策用のトークンが生成されていること
让我们来确认一下。
请参考相关资料。
-
- Spring Security
-
- Spring SecurityでWebの認証と認可を制御する – Developers.IO
- Spring Securityでユーザ認証を実装してみる – ももいろテクノロジー