SpringSecurity+Redis认证过程小结
作者:ME_._ME 发布时间:2021-07-21 11:38:11
由于今天用Security进行权限管理的时候出现了一些Bug,特此发这篇博客来补习一下对SpringSecurity的理解
前言引入
当今市面上用于权限管理的流行的技术栈组合是
ssm+shrio
SpringCloud+SpringBoot+SpringSecurity
这种搭配自然有其搭配的特点,由于SpringBoot的自动注入配置原理,在创建项目时就自动注入管理SpringSecurity的过滤器容器(DelegatingFilterProxy),而这个过滤器是整个SpringSercurity的核心。掌握着SpringSercurity整个权限认证过程,而SpringBoot很香的帮你将其自动注入了,而用ssm
去整合Security,将会耗用大量的配置文件,不易于开发,而Security的微服务权限方案,更是能和Cloud完美融合,于是Security比Shrio更强大,功能更齐全。
Security的核心配置文件
核心:Class SecurityConfig extends WebSecurityConfigurerAdapter
继承了WebSecurityConfigurerAdapter后我们关注于configure方法对于在整个安全认证的过程进行相关的配置,当然在配置之前我们先简单了解一下流程
简单的看了整个权限认证的流程,很轻易的总结得出,SpringSecurity核心的就是以下几种配置项了
* (Interceptor)
过滤器(Filter)
处理器(Handler,异常处理器,登录成功处理器)
那我们就首先通过配置来完成认证过程吧!!!!
Security的认证过程
假设我们要实现一下的认证功能
1. 是登录请求
我们需要先判断验证码是否正确(验证码过滤器,通过addFilerbefore实现前置拦截)
再判断用户名密码是否正确(使用自带的用户名密码过滤器,UsernamePasswordAuthenticationFilter)
配置异常处理器(Handler)通过IO流将异常信息写出
关于密码校验的流程:
UsernamePasswordAuthenticationFilter的密码校验规则是基于AuthenticationManagerBuilder(认证管理器)下的 UserDetailsService里的规则进行验证的:
其中的核心方法:
1.public UserDetails *loadUserByUsername(String username)
通过请求参数的用户名去数据库查询是否存在,存在则将其封装在UserDetails里面,而验证过程是通过AuthenticationManagerBuilder获取到UserDetail里的username和password来校验的,
这样我们就可以通过
配置yaml文件设置账号密码
通过数据库结合UserDetail来设置账号密码
(UserDetailsService中的方法,注意需要将UserDetailsService注入AuthenticationManagerBuilder中)
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
SysUser sysUser = sysUserService.getByUsername(username);
if (sysUser == null) {
throw new UsernameNotFoundException("用户名或密码不正确");
}
// 注意匹配参数,前者是明文后者是暗纹
System.out.println("是否正确"+bCryptPasswordEncoder.matches("111111",sysUser.getPassword()));
return new AccountUser(sysUser.getId(), sysUser.getUsername(), sysUser.getPassword(), getUserAuthority(sysUser.getId()));
}
通过了这个验证后,过滤器放行,不通过就用自定义或者默认的处理器处理
核心配置文件:
package com.markerhub.config;
import com.markerhub.security.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
LoginFailureHandler loginFailureHandler;
@Autowired
LoginSuccessHandler loginSuccessHandler;
@Autowired
CaptchaFilter captchaFilter;
@Autowired
JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
@Autowired
JwtAccessDeniedHandler jwtAccessDeniedHandler;
@Autowired
UserDetailServiceImpl userDetailService;
@Autowired
JwtLogoutSuccessHandler jwtLogoutSuccessHandler;
@Bean
JwtAuthenticationFilter jwtAuthenticationFilter() throws Exception {
JwtAuthenticationFilter jwtAuthenticationFilter = new JwtAuthenticationFilter(authenticationManager());
return jwtAuthenticationFilter;
}
@Bean
BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
private static final String[] URL_WHITELIST = {
"/login",
"/logout",
"/captcha",
"/favicon.ico",
};
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
// 登录配置
.formLogin()
.successHandler(loginSuccessHandler)
.failureHandler(loginFailureHandler)
.and()
.logout()
.logoutSuccessHandler(jwtLogoutSuccessHandler)
// 禁用session
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
// 配置拦截规则
.and()
.authorizeRequests()
.antMatchers(URL_WHITELIST).permitAll()
.anyRequest().authenticated()
// 异常处理器
.and()
.exceptionHandling()
.authenticationEntryPoint(jwtAuthenticationEntryPoint)
.accessDeniedHandler(jwtAccessDeniedHandler)
// 配置自定义的过滤器
.and()
.addFilter(jwtAuthenticationFilter())
.addFilterBefore(captchaFilter, UsernamePasswordAuthenticationFilter.class)
;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailService);
}
}
2. 不是登录请求
通过JwtfFilter来查看是否为登录状态
使用Redis整合时的注意事项
本质上还是编写过滤器链:
在登录请求前添加过滤器
注意验证码存储在redis的失效时间,如果超过失效时间将会被验证码 * 拦截下来
需要准备一个生成验证码的接口,存储在Redis中
使用完验证码需要将其删除
// 校验验证码逻辑
private void validate(HttpServletRequest httpServletRequest) {
String code = httpServletRequest.getParameter("code");
String key = httpServletRequest.getParameter("token");
if (StringUtils.isBlank(code) || StringUtils.isBlank(key)) {
System.out.println("验证码校验失败2");
throw new CaptchaException("验证码错误");
}
System.out.println("验证码:"+redisUtil.hget(Const.CAPTCHA_KEY, key));
if (!code.equals(redisUtil.hget(Const.CAPTCHA_KEY, key))) {
System.out.println("验证码校验失败3");
throw new CaptchaException("验证码错误");
}
// 一次性使用
redisUtil.hdel(Const.CAPTCHA_KEY, key);
}
来源:https://blog.csdn.net/qq_51131591/article/details/122308675


猜你喜欢
- 在java项目开发中。最开始换行符大家一般是在idea中设置新文件为LF,并且对旧文件通过IDEA下方的点击来更换换行符。很显然,对于几千文
- APP中可能会遇到一种需求,就是将当前所在位置的坐标传到服务器上,今天我提供三种途径去获取经纬度坐标信息,第一种是通过Android API
- Maven Repository仓库的具体使用不知道大家是不是这样,反正我访问官网的时候不是非常慢就是崩溃,所以我就将我用过的Maven依赖
- Java语言中反射 * 接口的解释与演示Java在JDK1.3的时候引入了 * 机制、可以运用在框架编程与平台编程时候捕获事件、审核数据
- java中 String和StringBuffer的区别实例详解String: &
- 环境准备JDK 1.8,Springboot 2.1.3.RELEASE,spring-boot-starter-aop.2.1.4.REL
- Spring发布了一个新工具Spring Native Beta,用于将现有的Spring Boot应用程序(用Java或Kotlin编写)
- ActiveMQ 结合 Spring 收发消息直接使用 ActiveMQ 的方式需要重复写很多代码,且不利于管理,Spring 提供了一种更
- 1.位置:如下:如果没有则在相同位置新建一个2. 添加端口号,修改:如图server.port=8080启动项目就会发现端口号已经成为你刚才
- 你平时是怎么读取文件的?使用流读取。是的没错,C#给我们提供了非常强大的类库(又一次吹捧了.NET一番),里面封装了几乎所有我们可以想到的和
- 本文实例分析了Android中BaseAdapter的用法。分享给大家供大家参考,具体如下:最近做一个项目,项目中用到了ListView,L
- 登录注册小代码,将学过的一些小知识融合在一起进行了使用,加深印象。本例中如果有注释不详细的地方,详见其它博客。功能介绍:简单的登录注册系统,
- 前言表之间的关系有几种:一对多、多对一、 一对一、多对多在多对一关系中,把多的部分拆成一个一个对象其实就是一对一关系,如账户和用户是多对一关
- 前言我身边有一部分开发的小伙伴,存在着这样一种习惯。某一天,突然看到某一款 App 上有个很漂亮的自定义控件(动画)效果,就会绞尽脑子想办法
- 1、什么是集合框架?在java中,有一套现成的数据结构,例如顺序表,链表,队列,栈,优先级队列,哈希表等,被封装成了相应的接口/类,供程序员
- 本文实例讲述了C#基于UDP进行异步通信的方法。分享给大家供大家参考。具体如下:服务器端:using System;using System
- 本文实例为大家分享了Android倒计时效果的具体代码,供大家参考,具体内容如下需求:a.在后台添加时,如果是今日直播,则需要添加开始时间(
- 本文实例讲述了C#获取U盘序列号的方法。分享给大家供大家参考。具体如下:using System.Management;private Li
- 一.内部类的介绍 内部类: 一个类定义在 另一个类 的 内部。 &
- 概述:开发过程中,看到有些界面用到一道光线在屏幕中掠过的效果,觉得挺炫的。所以查找相关资料自己实现了一遍。先上个预览图:实现思路:简单来说就