redis+springsecurity+mybtais-plus+JWT
01 引入依赖
xml
复制代码
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!--lombok依赖-->
<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>
<!-- 使用knife4j依赖 -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>2.0.9</version>
</dependency>
<!-- jwt依赖-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.10.3</version>
</dependency>
<!--redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--mybatisplus依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<!-- spring-security依赖-->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
02 配置系统文件
yml
复制代码
#配置redis的端口和mybatis---plus的数据源,swagger的配置信息
spring:
redis:
host: 127.0.0.1
port: 6379
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/text012?userSSL=false;serverTimezone=Asia/Shanghai
username: root
password: 1234
mvc:
pathmatch:
matching-strategy: ant_path_matcher
#开启驼峰转化,mapper的xml文件夹扫描
mybatis-plus:
config-locations: classpath:mapper/*.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
03 配置启动类
java
复制代码
@SpringBootApplication
@MapperScan("com.example.demo.mapper")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
04 重写UserDetailsService接口
java
复制代码
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
//这是mybatis-plus所实现的数据操作层,不使用mybatis-plus就不写
@Autowired
private MsUserServiceImp msUserServiceImp;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//使用mybatis-plus,获取到账号密码数据
LambdaQueryWrapper<MsUser> qw=new LambdaQueryWrapper<>();
qw.eq(MsUser::getUsername,username);
MsUser user = msUserServiceImp.getOne(qw);
//下一步就是重写UserDetails接口
LoginUser loginUser = new LoginUser();
loginUser.setMsUser(user);
return loginUser;
}
}
05 重写UserDetails接口
java
复制代码
//前三个是lombok的模块化配置,第四个是redis的序列化配置
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class LoginUser implements UserDetails {
//首先要写一个与数据库内表对应的实体类
private MsUser msUser;
//重写审核方法
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
//返回实体类MsUser中Password(密码)和Username(账号名对应的属性),将判断方法的返回值都改为true
@Override
public String getPassword() {
return msUser.getPassword();
}
@Override
public String getUsername() {
return msUser.getUsername();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
四个关键点
1.UserDetails接口的实现类需要一个实体类属性(类似MsUser)
2.getPassword和getUsername方法需要返回实体类(MsUser)中代表账号名和密码的属性的值
3.五个判断账号使用的情况的方法需要返回true,不然无法正常使用
06 重写springSecurity的配置类
- 实现WebSecurityConfigurerAdapter接口
java
复制代码
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//需要自定义JWT过滤器
@Autowired
private JWTFilter jwtFilter;
//设置密码的加密方式
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
//关闭原有的登录接口和页面,后端只完成接口即可,让前端去画登录界面
@Override
protected void configure(HttpSecurity http) throws Exception {
http// 将自己定义的过滤器加到UsernamePasswordAuthenticationFilter之前
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
http
//关闭csrf
.csrf().disable()
//不通过Session获取SecurityContext
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
// 对于登录接口 允许匿名访问
.antMatchers("/msUser/login").anonymous()
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated();
}
//顺便设置JWT的token验证方式,这里我没重写,使用springsecurity原有的实现方式
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
五个关键点
1.自定义JWT过滤器
2.设置密码的加密方式
3.addFilterBefore,把自定义的JWT的过滤器加到UsernamePasswordAuthenticationFilter过滤器前
4.关闭csrf(原有的登录界面和接口)
5.设置JWT的token验证方式
07 写登录实现类
- 我这里采用mybatis-plus实现从数据库获取数据,其他方式也可
java
复制代码
@Service
public class MsUserServiceImp extends ServiceImpl<MsUserMapper, MsUser>
implements IMsUserService {
//注入AuthenticationManager对象
@Autowired
private AuthenticationManager authenticationManager;
//写一个用于使用Redis工具类
@Autowired
private RedisUtil redisUtil;
//AjaxResult是我用于设置返回的工具类,不重要
@Override
public AjaxResult login(MsUser user) {
//token的验证
UsernamePasswordAuthenticationToken token=new UsernamePasswordAuthenticationToken(user.getUsername(),user.getPassword());
Authentication authentication=authenticationManager.authenticate(token);
if (Objects.isNull(authentication)){
throw new RuntimeException("认证失败");
}
//合格说明通过
LoginUser loginUser=(LoginUser) authentication.getPrincipal();
//使用JWT创建token,这里我封装了一个JWT的工具类
String jwt= JWTUtil.createToken(loginUser.getMsUser());
try {
redisUtil.setCacheObject("user:"+loginUser.getMsUser().getUserId(),loginUser);
}catch (Exception e){
e.printStackTrace();
}
return AjaxResult.success("登录成功",jwt);
}
}
三个关键点
1.调用springsecurity的工具类验证前端参数
2.使用JWT工具类生成token
3.redis的数据储存
08 测试
java
复制代码
@RestController
@RequestMapping("/msUser")
public class MsUserController {
@Autowired
private MsUserServiceImp userServiceImp;
@PostMapping("/login")
public AjaxResult<String> login(MsUser user) {
System.out.println(user);
return userServiceImp.login(user);
}
}