一、Spring Security内部认证流程

  1. 用户首次登录提交用户名和密码后spring security 的UsernamePasswordAuthenticationFilter把用户名密码封装Authentication对象

  2. 然后内部调用ProvideManagerauthenticate方法进行认证,然后ProvideManager进一步通过内部调用DaoAuthencationPrioviderauthenticate方法进行认证

  3. DaoAuthencationPriovider通过调用UserDetailsService的实现类InMemoryDetialManagerloadUserByUsername方法查询用户,并把查询到的用户信息封装成一个UserDetails对象。注意InMemoryDetialManage是从内存中查询用户信息的,所以我们要定制化实现UserDetailsService接口来达到从数据库查询用户信息。

  4. 通过PasswordEncode对比返回的UserDetails对象的密码和Authentication对象的密码是否一致,如果密码正确就把UserDetails中的权限信息设置到Authentication对象中

  5. 如果成功返回Authentication对象就使用SecurityContextHolder.getContext().setAuthentication方法存储改对象,然后其他过滤器就会通过SecurityContextHolder来获取当前用户信息。

二、自定义认证流程

我们要定制化实现UserDetailsService接口来达到从数据库查询用户信息,所以重新写一个UserDetailsServiceImpl实现类。然后认证通过使用用户id生成一个jwt(也就是token),然后用userId 作为key,用户信息作为value存入redis中。用户第一次登陆认证流程如下图。


导入依赖

  <!--SpringSecurity启动器--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><!--redis依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!--fastjson依赖--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId></dependency><!--jwt依赖--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId></dependency>

UserDetailsServiceImpl代码

@Service
public class UserDetailServiceImpl implements UserDetailsService {@Resourceprivate UserMapper userMapper;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//根据用户名查询用户信息LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(User::getUserName,username);User user = userMapper.selectOne(queryWrapper);//判断是否查到用户  如果没查到抛出异常if(Objects.isNull(user)){throw new RuntimeException("用户名不存在");}//返回用户信息// TODO 查询权限信息封装return new LoginUser(user);}
}

BlogLoginServiceImpl 登陆认证代码

@Service
public class BlogLoginServiceImpl implements BlogLoginService {@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate RedisCache redisCache;@Overridepublic ResponseResult login(User user) {UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName(),user.getPassword());Authentication authenticate = authenticationManager.authenticate(authenticationToken);//判断是否认证通过if(Objects.isNull(authenticate)){throw new RuntimeException("用户名或密码错误");}//获取userid 生成tokenLoginUser loginUser = (LoginUser) authenticate.getPrincipal();String userId = loginUser.getUser().getId().toString();String jwt = JwtUtil.createJWT(userId);//把用户信息存入redisredisCache.setCacheObject("bloglogin:"+userId,loginUser);//把token和userinfo封装 返回UserInfoVo userInfoVo = BeanCopyUtil.copyBean(loginUser.getUser(), UserInfoVo.class);BlogUserLoginVo blogUserLoginVo = new BlogUserLoginVo(jwt, userInfoVo);//把User转换成UserInfoVoreturn ResponseResult.okResult(blogUserLoginVo);}
}

SecurityConfig配置类


@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic PasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}@Overrideprotected void configure(HttpSecurity http) throws Exception {http//关闭csrf.csrf().disable()//不通过Session获取SecurityContext.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()// 对于登录接口 允许匿名访问.antMatchers("/login").anonymous()// 除上面外的所有请求全部不需要认证即可访问.anyRequest().permitAll();http.logout().disable();//允许跨域http.cors();}@Override@Beanpublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}
}

JwtUtil工具类

public class JwtUtil {//有效期为public static final Long JWT_TTL = 24*60 * 60 *1000L;// 60 * 60 *1000  一个小时//设置秘钥明文public static final String JWT_KEY = "hhh";public static String getUUID(){String token = UUID.randomUUID().toString().replaceAll("-", "");return token;}/*** 生成jtw* @param subject token中要存放的数据(json格式)* @return*/public static String createJWT(String subject) {JwtBuilder builder = getJwtBuilder(subject, null, getUUID());// 设置过期时间return builder.compact();}/*** 生成jtw* @param subject token中要存放的数据(json格式)* @param ttlMillis token超时时间* @return*/public static String createJWT(String subject, Long ttlMillis) {JwtBuilder builder = getJwtBuilder(subject, ttlMillis, getUUID());// 设置过期时间return builder.compact();}private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;SecretKey secretKey = generalKey();long nowMillis = System.currentTimeMillis();Date now = new Date(nowMillis);if(ttlMillis==null){ttlMillis=JwtUtil.JWT_TTL;}long expMillis = nowMillis + ttlMillis;Date expDate = new Date(expMillis);return Jwts.builder().setId(uuid)              //唯一的ID.setSubject(subject)   // 主题  可以是JSON数据.setIssuer("sg")     // 签发者.setIssuedAt(now)      // 签发时间.signWith(signatureAlgorithm, secretKey) //使用HS256对称加密算法签名, 第二个参数为秘钥.setExpiration(expDate);}/*** 创建token* @param id* @param subject* @param ttlMillis* @return*/public static String createJWT(String id, String subject, Long ttlMillis) {JwtBuilder builder = getJwtBuilder(subject, ttlMillis, id);// 设置过期时间return builder.compact();}public static void main(String[] args) throws Exception {String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJjYWM2ZDVhZi1mNjVlLTQ0MDAtYjcxMi0zYWEwOGIyOTIwYjQiLCJzdWIiOiJzZyIsImlzcyI6InNnIiwiaWF0IjoxNjM4MTA2NzEyLCJleHAiOjE2MzgxMTAzMTJ9.JVsSbkP94wuczb4QryQbAke3ysBDIL5ou8fWsbt_ebg";Claims claims = parseJWT(token);System.out.println(claims);}/*** 生成加密后的秘钥 secretKey* @return*/public static SecretKey generalKey() {byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");return key;}/*** 解析** @param jwt* @return* @throws Exception*/public static Claims parseJWT(String jwt) throws Exception {SecretKey secretKey = generalKey();return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();}}

redis缓存配置类

@Configuration
public class RedisConfig {@Bean@SuppressWarnings(value = { "unchecked", "rawtypes" })public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory){RedisTemplate<Object, Object> template = new RedisTemplate<>();template.setConnectionFactory(connectionFactory);FastJsonRedisSerializer serializer = new FastJsonRedisSerializer(Object.class);// 使用StringRedisSerializer来序列化和反序列化redis的key值template.setKeySerializer(new StringRedisSerializer());template.setValueSerializer(serializer);// Hash的key也采用StringRedisSerializer的序列化方式template.setHashKeySerializer(new StringRedisSerializer());template.setHashValueSerializer(serializer);template.afterPropertiesSet();return template;}
}

下次用户再次发请求时带token(相对于没有前后端分离时的session)来进行访问,如果没有携带则不让访问,如果有就经过一个jwt认证过滤器来获取token,解析token,最后获取userId,封装成Authentication对象存入SecurityContextHolderredis中以便其他过滤器或者资源来获取当前用户请求信息

最后感悟:springboot约定大于配置,许多接口都可以自定义,达到定制化功能,这也体现了springboot的强大,还有许多功能还没完成,授权功能和流程将在后续完成,敬请期待。

Spring Security进行登录认证和授权相关推荐

  1. spring security+jwt 登录认证

    spring security+jwt 登录认证 1.综述 2.版本与环境 3.架构 4.数据库认证逻辑图 5.案例 security+jwt 5.1引入依赖 5.2新建工具类 5.2新建组件类 5. ...

  2. Spring Security + JWT 实现认证和授权

    整体流程 用户登录成功后,服务端返回 jwt token 给客户端.token 中包含用户名,失效时间等信息.客户端保存 token,服务端不进行存储.客户端每次发送请求的时候,带上 token,服务 ...

  3. 清晰搞懂Spring Security的登录认证

    文章目录 前言 1.简介 2.登录认证 2.1.过滤器链 2.2.认证流程 2.3.大思路分析 3.撸袖开干 3.1.环境搭建 3.1.1.数据库 3.1.2.项目搭建 3.1.3.工具类.部分配置类 ...

  4. Spring Security OAuth2.0认证授权

    文章目录 1.基本概念 1.1.什么是认证 1.2 什么是会话 1.3什么是授权 1.4授权的数据模型 1.4 RBAC 1.4.1 基于角色的访问控制 2.基于Session的认证方式 3.整合案例 ...

  5. 自定义request_Spring Security 自定义登录认证(二)

    一.前言 本篇文章将讲述Spring Security自定义登录认证校验用户名.密码,自定义密码加密方式,以及在前后端分离的情况下认证失败或成功处理返回json格式数据 温馨小提示:Spring Se ...

  6. Spring Security 实战干货:OAuth2授权回调的核心认证流程

    1. 前言 我们在上一篇 Spring Security 实战干货:OAuth2 授权回调的处理机制 对 OAuth2 服务端调用客户端回调的流程进行了图解, 今天我们来深入了解 OAuth2 在回调 ...

  7. Spring Security OAuth2.0认证授权知识概括

    Spring Security OAuth2.0认证授权知识概括 安全框架基本概念 基于Session的认证方式 Spring Security简介 SpringSecurity详解 分布式系统认证方 ...

  8. 从零开始超详细的Spring Security OAuth2.0实现分布式系统授权(注册中心+网关+认证授权服务(JWT令牌验证)+资源调用服务)

    文章目录 一.OAuth2.0 1.介绍 2.例子 3.执行流程 二.Spring Cloud Security OAuth2 1.环境介绍 2.认证流程 三.整合分布式项目 1.技术方案 2.项目结 ...

  9. Spring Security OAuth2.0认证授权五:用户信息扩展到jwt

    历史文章 [Spring Security OAuth2.0认证授权一:框架搭建和认证测试] [Spring Security OAuth2.0认证授权二:搭建资源服务] [Spring Securi ...

最新文章

  1. 搜索引擎索引之如何更新索引
  2. 漫反射 高光反射_如何有效地使用反射
  3. linux ftp mysql_linux下ftp和ftps以及ftp基于mysql虚拟用户认证服务器的搭建
  4. Socket简单介绍(通过NSStream)
  5. 担心再次被起诉?马斯克已删除特斯拉可能几个月内成为最大公司推文
  6. css随机数,在LESS CSS中生成随机数?
  7. zookeeper和eureka的对比
  8. Opencv实现多幅图片拼接在一起
  9. 2010——满地遍是网页防篡改和WAF
  10. PDF如何复制页面,PDF复制页面这种方法就够了
  11. 最新Everest 企业版(AIDA64)使用SQL保存数据的方法介绍
  12. HTML+CSS实战:做一个京东登录页面
  13. 认识VBA------------------VBA基础
  14. 单点登录原理与代码实现
  15. TKMybatis的使用大全和例子(example、Criteria、and、or)
  16. Win7下给电脑加域,及遇到的问题。欢迎留言
  17. FC游戏 《三国志2-霸王的大陆》攻略
  18. 小学4年级计算机课作业题目,部编版小学语文四年级下册课堂同步作业试题及答案(全册).doc...
  19. HTML+CSS静态页面网页设计作业——甜品奶茶店(19页) HTML5网页设计成品_学生DW静态网页设计_web课程设计网页制作
  20. wps文字 用WPS如何演示制作英语有声读物

热门文章

  1. 青云科技以开放姿态打造低代码平台
  2. 百病之源五脏为根(国粹---gt;中医;在此提倡自然疗法!)
  3. android 组件导出,阳光沙滩-android组件化项目,build生成的文件重复的情况
  4. java.lang.NoSuchMethodError的解决办法
  5. 【FI】SAP标准成本计算和发布
  6. Maven3.5.3下载安装与环境配置
  7. c语言编程转化为vba编程,PPT VBA编程.doc
  8. Qt: 表格(QTableWidget)隐藏自动生成的序号列(行头)
  9. java中获取输入的几种方式
  10. 每日一道leetcode(python)695. 岛屿的最大面积