SpringSecurity+Redis认证过程小结

网友投稿 737 2022-11-10

SpringSecurity+Redis认证过程小结

SpringSecurity+Redis认证过程小结

目录前言引入Security的核心配置文件Security的认证过程1. 是登录请求2. 不是登录请求使用Redis整合时的注意事项

由于今天用Security进行权限管理的时候出现了一些Bug,特此发这篇博客来补习一下对SpringSecurity的理解

前言引入

当今市面上用于权限管理的流行的技术栈组合是

ssm+shrioSpringCloud+SpringBoot+SpringSecurity

这种搭配自然有其搭配的特点,由于SpringBoot的自动注入配置原理,在创建项目时就自动注入管理SpringSecurity的过滤器容器(DelegatingFilterProxy),而这个过滤器是整个SpringSercurity的核心。掌握着SpringSercurity整个权限认证过程,而SpringBoot很香的帮你将其自动注入了,而用ssm去整合Security,将会耗用大量的配置文件,不易于开发,而Security的微服务权限方案,更是能和Cloud完美融合,于是SecurZbGThurity比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

JwtLogoutSurZbGThuccessHandler 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);

}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:我心目中的好编程语言
下一篇:ListContains, Exists, Any之间的优缺点对比
相关文章

 发表评论

暂时没有评论,来抢沙发吧~