03 Spring Security 入门实例
目录结构

依赖
我们还是使用 Maven 管理依赖,Kotlin 作为开发语言,在 Spring Boot 的版本上,我们选择 版本。其中除了必须的依赖之外还引入了 、,以及主角 。
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.3.3.RELEASE
com.example
security
0.0.1-SNAPSHOT
security
Demo project for Spring Boot
1.8
1.3.72
org.springframework.boot
spring-boot-starter-security
org.springframework.boot
spring-boot-starter-thymeleaf
org.springframework.boot
spring-boot-starter-web
com.fasterxml.jackson.module
jackson-module-kotlin
org.jetbrains.kotlin
kotlin-reflect
org.jetbrains.kotlin
kotlin-stdlib-jdk8
org.springframework.boot
spring-boot-starter-test
test
org.junit.vintage
junit-vintage-engine
org.springframework.security
spring-security-test
test
${project.basedir}/src/main/kotlin
${project.basedir}/src/test/kotlin
org.springframework.boot
spring-boot-maven-plugin
org.jetbrains.kotlin
kotlin-maven-plugin
-Xjsr305=strict
spring
org.jetbrains.kotlin
kotlin-maven-allopen
${kotlin.version}
路径映射
package com.example.security.configuration
import org.springframework.context.annotation.Configuration
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
@Configuration
class MvnConfig : WebMvcConfigurer {
override fun addViewControllers(registry: ViewControllerRegistry) {
registry.addViewController("/home").setViewName("home")
registry.addViewController("/").setViewName("home")
registry.addViewController("/hello").setViewName("hello")
registry.addViewController("/login").setViewName("login")
}
}
这里我们使用统一的配置 MVC-View 的关系映射,不再创建多个 Controller 了。主要的就是配置四对 URL-页面的映射,并没有什么其他功能。
安全框架配置
package com.example.security.configuration
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
import org.springframework.security.core.userdetails.User
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.provisioning.InMemoryUserDetailsManager
@Configuration
@EnableWebSecurity
class WebSecurityConfig : WebSecurityConfigurerAdapter() {
override fun configure(http: HttpSecurity) {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll()
}
@Bean
override fun userDetailsService(): UserDetailsService {
val user = User
.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build()
return InMemoryUserDetailsManager(user)
}
}
注解简单的理解就是字面意思启用 Spring Security 对与 web 的安全支持,并且同事继承了 类,复用了其中的一个默认配置,也自定义了 Spring Security 配置。
方法我们从方法名上就可以知道它一个用来设置某些东西的,而形参的类型是 可以简单的推断出是一个关于 http 请求的一个设置方法。既然是关于一个 http 相关的,那么就大概就是管什么请求路径可以访问,什么请求路径不可以访问,某个角色可以访问那些个路径之类的。
上面的示例中代码所进行的配置大致意思就是:
路径 以及 可以随意访问,不用登录就可以访问
表示的意思是,剩下的任何路径都要登录才能访问
通过 是登录的入口地址
登出、注销是通过 作为出口的地址
方法其实是我们通过使用内存的方式来模拟一个用户用的,用户名是 user,密码是 password,对应的角色是 USER。
页面
页面我们在前面引入了 ,来作为视图层的实现。
home.html
Home
Welcome!
Click here to see a greeting.
很简单的一个欢迎页,然后点击按钮会访问 路径。
hello.html
Hello
Hello [[${#httpServletRequest.remoteUser}]]!
当成功访问 路径后会调到 hello.html 页面,但是有一个问题是,我们在之前的安全配置中,没有指明 路径是可以不用登录直接访问的,那么结果就是浏览器自动跳转到 login 登录页面
login.html
Login
Invalid username and password.
You have been logged out.
页面包含最基本的一个 标签,需要输入用户名和密码,登录请求的地址就是 ;额外的当我们输入的用户名和密码是不对的 Spring Security 会复用该登录页面,返回类似 /login?eror 的格式,同样的登出注销是一样的,格式类似 /login?logout
项目启动
欢迎首页(home.html)

点击 按钮应该会跳转到 hello.html 页面,但是因为框架检测到我们没有登录,自动的转到了 login.html 的登录页面。

这时我们用在代码里固定模拟的用户以及密码(user/password),进行登录尝试。

页面提示登录成功,我们再来试一下登出,点击 按钮。

果然,登出的页面是复用的登录的页面,然是在最上面第一行输出了提示,“You have been logged out.” 来区分是登录还是登出的动作。
最后,我试下登录不成功的情况,输入错误的用户名或者密码。

到此为止一个入门的简单的 Spring Security 例子就完成了。
该例子可以在 Spring 的 github 代码仓库中找到,只不过是简单用 Kotlin 进行了重新写了一遍而已。