环境:SpringToolSuite4 或者其它spring boot开发环境,mysql数据库
技术:spring security、spring boot 、mybatisplus、thymeleaf(前端)
备注:这里只做登录(身份)认证,不做权限认证,要学习权限认证请及时跳转。
1.创建数据库
因为只做登录认证,所以我的数据库很简单,只有账号和密码。我通常使用workbench可视平台直接创建,但这里为了保持编码、字段类型等属性一致,建议使用下方提供的SQL语句进行创建。因为数据表可能看起来一样,但是字段类型并不一样,比如我的password用的是varchar(12),而你的可能用的是varchar(3)或者直接用了int,这样就很容易出错了。还有一个就是编码问题,比如我用的是utf-8,而你用的是GBK编码,这样在传中文时也容易出现乱码。我也是菜鸟,这是我的一些总结。
2.数据库SQL创建语句
CREATE DATABASE IF NOT EXISTS `datas` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `datas`;
DROP TABLE IF EXISTS `user`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `user` (
`username` varchar(12) NOT NULL,
`password` varchar(12) DEFAULT NULL,
PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
LOCK TABLES `user` WRITE;
/*!40000 ALTER TABLE `user` DISABLE KEYS */;
INSERT INTO `user` VALUES ('admin','123456'),('root','321'),('user','123');
/*!40000 ALTER TABLE `user` ENABLE KEYS */;
UNLOCK TABLES;
3.创建spring boot工程
————————————————————————————
————————————————————————————
————————————————————————————
———————————————————————————————————————————————————————————————————————————————————————
选择Security、Web、Mysql Driver等模块,finish快速创建工程
引入thymeleaf和mybatis-plus包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.2</version>
</dependency>
pom.xml文件全部内容如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.mp</groupId>
<artifactId>springboot-security-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-security-2</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<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>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-core -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
4.创建数据库连接配置文件
使用yaml文件类型创建,文件名:application.yml
内容如下:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/datas?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: 123456
5.调整工程目录结构
创建 entity 、dao等包目录
6.创建实体类UserDto.java
package com.fiblue.home.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@TableName(value = "user")
public class UserDto{
@TableId(value = "username",type =IdType.NONE)
private String username;
private String password;
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;
}
@Override
public String toString() {
return "UserDto [username=" + username + ", password=" + password + "]";
}
}
这里的@TableName在实体类名和数据库表名不一致时必须要用上。至于在表名和类名一致时是否需要用还有待探讨,我也没有求证过。后面的 toString()方法是我在Test单元测试时增加的,可以不用写。
7.创建UserMapper接口
package com.fiblue.home.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.fiblue.home.entity.UserDto;
public interface UserMapper extends BaseMapper<UserDto> {
}
8.增加@MapperScan注解
在***Appllication.java启动类中增加@MapperScan注解,即告诉启动类在哪里扫描到mapper接口。
package com.fiblue.home;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.fiblue.home.mapper")
public class SpringSecurity2Application {
public static void main(String[] args) {
SpringApplication.run(SpringSecurity2Application.class, args);
}
}
9.创建Dao层操作类UserDao.java
package com.fiblue.home.dao;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.fiblue.home.entity.UserDto;
import com.fiblue.home.mapper.UserMapper;
@Repository
public class UserDao {
@Autowired
private UserMapper userMapper;
public UserDto userQuery(String username){
Map<String, Object> params = new HashMap<>();
params.put("username", username);
List<UserDto> users = new LinkedList<UserDto>();
users=userMapper.selectByMap(params);
if(users!=null&&users.size()>=1) {
return users.get(0);
}
else {
return null;
}
}
}
以上三步涉及一些Mybatis-plus的技术,大家可以去了解一些,这个比mybatis还要先进一些。
10.创建Service层操作类UserService.java
package com.fiblue.home.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.fiblue.home.dao.UserDao;
import com.fiblue.home.entity.UserDto;
@Service
public class UserService implements UserDetailsService{
@Autowired
private UserDao userDao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException{
UserDto userDto=userDao.userQuery(username);
if (userDto==null) {
return null;
}
UserDetails userDetails=User.withUsername(userDto.getUsername()).password(userDto.getPassword()).authorities("p1").build();
return userDetails;
}
}
这里可能会有疑问,开始说不使用权限认证,为什么这里出现.authorities(“p1”)这个方法?因为如果不使用.authorities()或者.authorities()为空就会导致security报错,本人尚未找到解决办法。所以这里随便受一个p1的权限,只要后面资源不对这个权限进行拦截,那么就基本的访问并不出现问题。
11.创建配置类SecurityConfig.java
package com.fiblue.home.securityconfig;
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.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
@Override
protected void configure(HttpSecurity http) throws Exception {
// TODO Auto-generated method stub
http
.cors().disable()
.authorizeRequests()
.antMatchers("/", "/index").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").permitAll()
.loginProcessingUrl("/login")
.defaultSuccessUrl("/success")
.and()
.logout().permitAll();
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();//不使用加密
}
}
这里不对密码进行加密处理,所以使用了NoOpPasswordEncoder.
12.创建首页index.html
该页面及以下两个页面均在src/main/resources/templates下创建,注意这里引入了thymeleaf命名空间,否则会报错。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<a th:href="@{/login}">登录</a>
</body>
</html>
13.创建登录页面login.html
<!doctype html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<meta charset="UTF-8" />
<title>login</title>
</head>
<body>
<div th:if="${param.error}">无效用户名和密码</div>
<div th:if="${param.logout}">已登出</div>
<form th:action="@{/login}" method="post">
<div><label for="username">User Name: <input type="text" name="username" /></label></div>
<div><label for="password">password: <input type="password" name="password" /></label></div>
<div><input type="submit" value="Sign In"/></div>
</form>
</body>
</html>
14.创建登录成功界面 success.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>登录成功</title>
</head>
<body>
<p th:size="88">登录成功</p>
</body>
</html>
15.创建访问控制类PageController.java
package com.fiblue.home.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class PageController {
@RequestMapping("/index")
public String index() {
return "/index";
}
@RequestMapping("/login")
public String login() {
return "/login";
}
@RequestMapping("/success")
public String success() {
return "/success";
}
}
通过以上15个步骤,该Spring Security基础功能已经创建完成,但要注意的是其中个人写的类可能其包名和大家的不一致,从而导致一些问题,直接复制粘贴时应检查这些问题。如下图:
——————————————————————————————————————————————————————————
16.运行结果
1.index.html
2.login.html
3.success.html
本教程到此结束,谢谢大家!