前情提要:SpringSecurity在Springboot中的使用(一)
本文源码:demo2
与上一个案例相比,本次案例实现了注册功能,和通过查询数据库的用户实现登录功能。
新建一个springboot项目,其中的pom.xml如下配置:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</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.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
首先建立一个数据库,取名随意,我取的是demo。
spring.datasource.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&useSSL=true
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# jpa
spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
User.java
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String username;
private String password;
private String role = "ROLE_USER";
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}
UserDao.java
public interface UserDao extends JpaRepository<User, Integer> {
User findByUsername(String username);
}
UserService.java
public interface UserService {
void register(User user);
User findByUsername(String username);
}
UserServiceImpl.java
@Service
public class UserServiceImpl implements UserService {
@Resource(name = "userDao")
private UserDao userDao;
@Override
public void register(User user) {
encryptPassword(user);
userDao.save(user);
}
@Override
public User findByUsername(String username) {
return userDao.findByUsername(username);
}
/**
* 加密密码
*/
private void encryptPassword(User userEntity){
String password = userEntity.getPassword();
password = new BCryptPasswordEncoder().encode(password);
userEntity.setPassword(password);
}
}
@Controller
public class HelloController {
@Resource(name = "userServiceImpl")
private UserService userService;
@GetMapping("/")
public String index() {
return "index";
}
@GetMapping("/hello")
public String hello() {
return "hello";
}
@RequestMapping("/login")
public String login() {
return "login";
}
@GetMapping("/register")
public String register() {
return "register";
}
@PostMapping("/register")
public String register2(User user) {
User u = userService.findByUsername(user.getUsername());
if (u == null) {
userService.register(user);
return "redirect:/register?success";
}
return "redirect:/register?error";
}
}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页title>
head>
<body>
<h1>欢迎使用Spring Securityh1>
<p>点击<a href="/hello">这里a>打个招呼吧p>
body>
html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>欢迎title>
head>
<body>
<h1>hello worldh1>
<form th:action="@{/logout}" method="post">
<input type="submit" value="注销"/>
form>
body>
html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>登录title>
head>
<body>
<h1>欢迎用户登录h1>
<div th:if="${param.error}">用户名或密码错误div>
<form th:action="@{/login}" method="post" autocomplete="off">
<table>
<tr>
<td><label for="username">用户名label>td>
<td><input type="text" id="username" name="username">td>
tr>
<tr>
<td><label for="password">密码label>td>
<td><input type="password" id="password" name="password">td>
tr>
<tr>
<td><input type="submit" value="提交">td>
<td><input type="button" value="注册" onclick="register()">td>
tr>
table>
form>
body>
<script>
function register() {
window.location.href = 'http://localhost:8080/register';
}
script>
html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>注册title>
head>
<body>
<h1>新用户注册h1>
<form th:action="@{/register}" method="post" autocomplete="off">
<table>
<tr>
<td><label for="username">用户名label>td>
<td><input type="text" id="username" name="username">td>
tr>
<tr>
<td><label for="password">密码label>td>
<td><input type="password" id="password" name="password">td>
tr>
<tr>
<td><input type="submit" value="提交">td>
<td><input type="button" value="登录" onclick="toLogin()">td>
tr>
table>
form>
body>
<script>
function toLogin() {
window.location.href = "http://localhost:8080/login";
}
script>
<script th:inline="javascript">
var msgError = /*[[${param.error}]]*/ 'haha';
var msgSuccess = /*[[${param.success}]]*/ 'haha';
if (msgError != null) {
alert('注册失败,该用户名已存在');
}
if (msgSuccess) {
alert('注册成功,您现在可以登录');
}
script>
html>
实现UserDetailsService接口,重写loadUserByUsername()方法。
AnyUserDetailsService.java
@Service
public class AnyUserDetailsService implements UserDetailsService {
private final UserService userService;
@Autowired
AnyUserDetailsService(UserService userService){
this.userService = userService;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
com.example.demo.entity.User userEntity = userService.findByUsername(username);
if (userEntity == null){
throw new UsernameNotFoundException("用户不存在!");
}
List<SimpleGrantedAuthority> simpleGrantedAuthorities = createAuthorities(userEntity.getRole());
return new User(userEntity.getUsername(), userEntity.getPassword(), simpleGrantedAuthorities);
}
/**
* 权限字符串转化
*
* 如 "USER,ADMIN" -> SimpleGrantedAuthority("USER") + SimpleGrantedAuthority("ADMIN")
*
* @param roleStr 权限字符串
*/
private List<SimpleGrantedAuthority> createAuthorities(String roleStr){
String[] roles = roleStr.split(",");
List<SimpleGrantedAuthority> simpleGrantedAuthorities = new ArrayList<>();
for (String role : roles) {
simpleGrantedAuthorities.add(new SimpleGrantedAuthority(role));
}
return simpleGrantedAuthorities;
}
}
WebSecurityConfig.java
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private AnyUserDetailsService anyUserDetailsService;
@Autowired
public void setAnyUserDetailsService(AnyUserDetailsService anyUserDetailsService){
this.anyUserDetailsService = anyUserDetailsService;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.antMatchers("/register").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder builder) throws Exception{
builder.userDetailsService(anyUserDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}
}
启动项目,来看一下效果吧
启动项目后,访问http://localhost:8080/:
点击超链接"这里"访问/hello,由于没有登录,页面将被重定向到/login页面:
我们现在还没有注册,先注册一个,点击注册按钮,跳转到注册页面:
随便注册一个用户,点击提交,会有弹出框提示注册成功,然后我们点击登录按钮进行登录,登录成功会出现欢迎界面: