SpringSecurity系列——简单自定义登录流程
SpringSecurity认证
前后端分离的登录校验流程
前后端分离请求响应流程
SpringSecurity完整流程
SpringSecurity的原理其实是个过滤器链,其内部包含了各式各样功能各异的过滤器,通过这些过滤器,对消息进行拦截、放行、处理操作
如何查看过滤器
1.启动类中添加逻辑进行debug
2.打开评估输入表达式
run.getBean(DefaultSecurityFilterChain.class)
这里你可以看到filters中的共计16个过滤器了
修改流程
登录
- 自定义登录接口
1.1 调用ProviderManager的方法进行认证如果认证通过生成jwt
1.2 把用户信息存入redis中
- 自定义UserDetailsservice
在这个实现列中去查询数据库
校验
- 定义jwt认证过滤器
1.1 获取token
1.2 解析token获取其中的userId
1.3 从redis中获取用户信息
1.4 存入SecurityContextHolder
自定义登录流程
1.导入依赖
<dependencies>
<dependency>
<groupId>cn.fly</groupId>
<artifactId>JJWTUtil</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.17</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<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-web-services</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.79</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</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>
2.编写yaml
server:
port: 8080
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/syf14?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&zeroDateTimeBehavior=CONVERT_TO_NULL&allowPublicKeyRetrieval=true
username: root
password: syf20020816
3.编写entity,mapper
User
package com.example.ss1.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
@TableName("user")
public class User {
private Long id;
private String username;
private String password;
private String status;
private String nickname;
}
UserMapper
package com.example.ss1.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.ss1.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
4.自定义登录表单对象实现UserDetails接口
package com.example.ss1.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserLogin implements UserDetails {
//传入用户对象
private User user;
/**
* 判断权限信息
* @return
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
/**
* 判断是否未过期
* @return
*/
@Override
public boolean isAccountNonExpired() {
return true;
}
/**
* 判断账户是否未锁定
* @return
*/
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
/**
* 判断是否可以使用
* @return
*/
@Override
public boolean isEnabled() {
return true;
}
}
5.自定义UserDetailsServiceImpl实现UserDetailsService
package com.example.ss1.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.ss1.entity.User;
import com.example.ss1.entity.UserLogin;
import com.example.ss1.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
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 java.util.Objects;
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//查询用户信息
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getUsername, username).last("limit 1");
User user = userMapper.selectOne(queryWrapper);
//异常
if (Objects.isNull(user)){
throw new UsernameNotFoundException("用户名未发现");
}
//查询对应权限信息
//数据封装为UserDetails返回
return new UserLogin(user);
}
}
6.修改数据库密码
添加{noop}表示明文存储
7.测试
访问http://localhost:8080/demo
使用数据库中的用户进行登录!