SpringBoot 全家桶 | SpringSecurity实
2020-09-09 本文已影响0人
码农StayUp
本文源码:Gitee·点这里
介绍
Spring Security 是一个功能强大且高度可定制的身份证认证和访问控制框架。其最重要的两部分是认证(Authentication)和授权(Authorization)。
本实例使用框架:
- Spring Security 本次重点讲述的对象,其他引入的框架自行查阅资料学习
- Spring Data JPA 请参阅 SpringBoot 全家桶 | JPA实例详解
- MySQL
- Thymeleaf
Spring Security 后端实例
引入包
我们引入spring-boot-starter-security
包,同时为完成实例引入了其他的包,这里不多做介绍
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
配置数据源
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/springboot-security?charset=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: root
jpa:
show-sql: true
hibernate:
ddl-auto: update
Security配置文件
我们创建一个Security的配置类,并继承WebSecurityConfigurerAdapter
类,加上@EnableWebSecurity
注解,表示启用Security,下面看详细代码
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
private UserDao userDao;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/css/**", "/", "/index", "/loginPage").permitAll() // 无需认证
.anyRequest().authenticated() // 其他请求都需要认证
;
http.formLogin() // 开启登录,如果没有权限,就会跳转到登录页
.loginPage("/loginPage") // 自定义登录页,默认/login(get请求)
.loginProcessingUrl("/login") // 登录处理地址,默认/login(post请求)
.usernameParameter("inputEmail") // 自定义username属性名,默认username
.passwordParameter("inputPassword") // 自定义password属性名,默认password
;
http.rememberMe() // 开启记住我
.rememberMeParameter("rememberMe") // 自定义rememberMe属性名
;
http.logout() // 开启注销
.logoutUrl("/logout") // 注销处理路径,默认/logout
.logoutSuccessUrl("/") // 注销成功后跳转路径
;
http.csrf().disable(); // 禁止csrf
}
@Bean
public UserDetailsService userDetailsService() {
return username -> {
xyz.zyl2020.security.entity.User user = userDao.findByUsernameOrEmail(username, username);
if (user == null) {
throw new UsernameNotFoundException("账号或密码错误!");
}
String[] roleCodeArray = user.getRoles().stream().map(Role::getCode).toArray(String[]::new);
return User.withUsername(user.getUsername())
.password(user.getPassword())
.roles(roleCodeArray)
.build();
};
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
- 重写
configure(HttpSecurity http)
方法,用于配置http请求认证-
http.authorizeRequests()
为请求授权,可以定义哪些资源无需认证,哪些资源需要认证 -
http.formLogin()
开启form表单登录,可自定义登录页,登录请求处理,还有账号、密码使用的参数等 -
http.rememberMe()
开启记住我功能 -
http.logout()
开户注销功能,并可自定义注解成功跳转路径 -
http.csrf()
CSRF防护,默认是开启的。若开启,则在表单中增加input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
-
-
userDetailsService()
配置鉴权,用户验证用户及权限。此时可以从数据库中查出用户及权限信息,构建UserDetailsService
类并返回,进行下一步验证,由Spring Security自行验证 -
passwordEncoder()
配置密码编码格式,不启用会报下面异常,这里我们使用BCrypt
。在用户注册时,密码使用相同的编码格式存库,BCrypt.hashpw("password", BCrypt.gensalt())
2020-08-24 22:03:20.014 ERROR 4692 --- [nio-8080-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
......
Controller配置
@Controller
public class RouteController {
@RequestMapping({"/", "/index"})
public String index() {
return "index";
}
@GetMapping("/loginPage")
public String loginPage() {
return "login";
}
@GetMapping("/currentUser")
public String getUsername() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Object principal = authentication.getPrincipal();
if (principal == null) {
return null;
}
UserDetails userDetails = (UserDetails) principal;
return userDetails.getUsername();
}
}
-
index()
指向主页,对应resources/templates/index.html
-
loginPage()
指向登录页,对应resources/templates/login.html
Service层、Dao层、和实体类查阅下面的【完整代码】吧,另外用户、角色、及其关系的初始化,在test代码中
Spring Security 前端使用thymeleaf
登录页 - 表单的使用
<form class="form-signin" action="/login" method="post">
<h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
<label for="inputEmail" class="sr-only">Email address</label>
<input type="email" id="inputEmail" name="inputEmail" class="form-control" placeholder="Email address" required autofocus>
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" id="inputPassword" name="inputPassword" class="form-control" placeholder="Password" required>
<div class="checkbox mb-3">
<label>
<input type="checkbox" name="rememberMe"> Remember me
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
<p class="mt-5 mb-3 text-muted">© 2017-2020</p>
</form>
-
action="/login"
对应着后台配置loginProcessingUrl("/login")
,这两个路径要一致 - 用户名、密码、记住我的
name
名,与后台配置要保持一致
做好以前配置,提交表单后会将用户名、密码、记住我信息提交致后台进行认证授权
主页 - Thymeleaf与Security的集成
thymeleaf与Security集成,主要使用引入的thymeleaf-extras-springsecurity5
包
<!doctype html>
<html lang="en" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
// 代码省略...
</head>
<body>
<div class="d-flex flex-column flex-md-row align-items-center p-3 px-md-4 mb-3 bg-white border-bottom shadow-sm">
<h5 class="my-0 mr-md-auto font-weight-normal">Welcome!</h5>
<nav class="my-2 my-md-0 mr-md-3">
<div sec:authorize="!isAuthenticated()">
<a class="btn btn-outline-primary" href="/loginPage">Login</a>
</div>
<div sec:authorize="isAuthenticated()">
<span sec:authentication="name"></span>
<a class="btn btn-outline-primary" href="/logout">Logout</a>
</div>
</nav>
</div>
<div class="pricing-header px-3 py-3 pt-md-5 pb-md-4 mx-auto text-center">
<h1 class="display-4">Pricing</h1>
<p class="lead">Quickly build an effective pricing table for your potential customers with this Bootstrap example.
It’s built with default Bootstrap components and utilities with little customization.</p>
</div>
<div class="container">
<div class="card-deck mb-3 text-center">
<div class="card mb-4 shadow-sm" sec:authorize="hasAnyRole('FREE')">
<div class="card-header">
<h4 class="my-0 font-weight-normal">Free</h4>
</div>
<div class="card-body">
<h1 class="card-title pricing-card-title">$0 <small class="text-muted">/ mo</small></h1>
<ul class="list-unstyled mt-3 mb-4">
<li>10 users included</li>
<li>2 GB of storage</li>
<li>Email support</li>
<li>Help center access</li>
</ul>
<a class="btn btn-lg btn-block btn-primary" href="#">Get started</a>
</div>
</div>
<div class="card mb-4 shadow-sm" sec:authorize="hasAnyRole('PRO')">
<div class="card-header">
<h4 class="my-0 font-weight-normal">Pro</h4>
</div>
<div class="card-body">
<h1 class="card-title pricing-card-title">$15 <small class="text-muted">/ mo</small></h1>
<ul class="list-unstyled mt-3 mb-4">
<li>20 users included</li>
<li>10 GB of storage</li>
<li>Priority email support</li>
<li>Help center access</li>
</ul>
<a class="btn btn-lg btn-block btn-primary">Get started</a>
</div>
</div>
<div class="card mb-4 shadow-sm" sec:authorize="hasAnyRole('ENT')">
<div class="card-header">
<h4 class="my-0 font-weight-normal">Enterprise</h4>
</div>
<div class="card-body">
<h1 class="card-title pricing-card-title">$29 <small class="text-muted">/ mo</small></h1>
<ul class="list-unstyled mt-3 mb-4">
<li>30 users included</li>
<li>15 GB of storage</li>
<li>Phone and email support</li>
<li>Help center access</li>
</ul>
<a class="btn btn-lg btn-block btn-primary">Get started</a>
</div>
</div>
</div>
</div>
</body>
</html>
- 引入
xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
命名空间,便可在html中使用security功能了 -
sec:authorize="isAuthenticated()"
标签表示已验证通过,即登录成功 -
sec:authentication="name"
获取当前用户名 -
sec:authorize="hasAnyRole('FREE')"
表示拥有指定角色方可显示内容 -
sec:authorize="hasAnyAuthority('user:add')"
表示拥有指定权限方可显示内容
更多功能请参照官网
参考
- Spring Security
- thymeleaf-extras-springsecurity
- Thymeleaf + Spring Security integration basics
- Bootstrap4
完整代码
登录前.png登录页.png
登录后.png 福利.jpg