用 Spring Security 实现后台登录及权限认证功能
- 1.引入依赖
- 2.创建权限开放的页面
- 3.创建需要权限验证的页面
- 4.配置 Spring Security
- 4.1 配置 Spring MVC
- 4.2 配置 Spring Security
- 5.创建登录页面
- 6.测试权限
1.引入依赖
使用前需要引入相关依赖,见以下代码:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
</dependencies>
2.创建权限开放的页面
这个页面(welcome.html
)是不需要鉴权即可访问的,以区别演示需要鉴权的页面,见以下代码:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head><title>Spring Security 案例</title></head>
<body>
<h1>Welcome!</h1>
<p><a th:href="@{/home}">会员中心</a></p>
</body>
</html>
3.创建需要权限验证的页面
其实可以和不需要鉴权的页面一样,鉴权可以不在 HTML 页面中进行,见以下代码:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head><title>home</title></head>
<body>
<p>会员中心</p>
<p th:inline="text">Hello <span sec:authentication="name"></span></p>
<form th:action="@{/logout}" method="post">
<input type="submit" value="登出"/>
</form>
</body>
</html>
使用 Spring Security 5 之后,可以在模板中用 <span sec:authentication="name"></span>
或 [[${#httpServletRequest.remoteUser}]]
来获取用户名。登岀请求将被发送到 /logout
。成功注销后,会将用户重定向到 /login?logout
。
4.配置 Spring Security
4.1 配置 Spring MVC
可以继承 WebMvcConfigurer,具体使用见以下代码:
package com.example.demo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//设置登录处理操作
registry.addViewController("/home").setViewName("springsecurity/home");
registry.addViewController("/").setViewName("springsecurity/welcome");
registry.addViewController("/login").setViewName("springsecurity/login");
}
}
4.2 配置 Spring Security
Spring Security 的安全配置需要继承 WebSecurityConfigurerAdapter,然后重写其方法, 见以下代码:
package com.example.demo.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.crypto.bcrypt.BCryptPasswordEncoder;
@Configuration
// 指定为 Spring Security 配置类
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/welcome", "/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").defaultSuccessUrl("/home")
.and()
.logout().permitAll();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("admin").password("$2a$10$AlpMTGDkUfYJMnb3/uNT1.mLxLJng7Uplfzpv5yIqZTkYtYsiiYbO").roles("USER");
}
}
- @EnableWebSecurity 注解:集成了 Spring Security 的 Web 安全支持。
- @WebSecurityConfig:在配置类的同时集成了 WebSecurityConfigurerAdapter,重写了其中的特定方法,用于自定义 Spring Security 配置。Spring Security 的工作量都集中在该配置类。
configure(HttpSecurity)
:定义了哪些 URL 路径应该被拦截。configureGlobaI(AuthenticationManagerBuiIder)
:在内存中配置一个用户,admin
/pipi
,这个用户拥有 User 角色。- 确保
antMatchers(xxx).permitAll()
的配置在需要认证和授权的 URL 路径之前。因为 Spring Security 会按照配置文件的顺序来匹配 URL 路径,如果antMatchers(xxx).permitAll()
在后面,那么前面的认证和授权规则会覆盖掉它。 .logout().permitAll()
表示在 Spring Security 配置中,无论用户是否经过身份验证,都可以访问注销(logout
)页面。这意味着,即使是一个未经过身份验证的用户也可以访问注销功能,这在某些情况下可能是一个安全隐患。因此,这个配置通常用于开发环境或测试环境,以确保用户可以轻松地测试注销功能,而在生产环境中,出于安全考虑,通常会更加限制对注销页面的访问权限。
5.创建登录页面
登录页面要特别注意是否开启了 CSRF 功能。如果开启了,则需要提交 token
信息。创建的登录页面见以下代码:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head><title>Spring Security Example </title></head>
<body>
<div th:if="${param.error}">
无效的用户名或者密码
</div>
<div th:if="${param.logout}">
你已经登出
</div>
<form th:action="@{/login}" method="post">
<div><label> 用户名: <input type="text" name="username"/> </label></div>
<div><label> 密码: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="登录"/></div>
</form>
</body>
</html>
6.测试权限
启动项目,访问首页 http://localhost:8080
。
单击 “会员中心”,尝试访问受限的页面 http://localhost:8080/home
。由于未登录,结果被强制跳转到登录页面 http://localhost:8080/login
。
输入正确的用户名和密码 (admin, pipi)
之后,跳转到之前想要访问的 /home
, 显示用户名 admin
。
单击 “登出” 按钮,回到登录页面。