若依管理系统——前后端分离版(二)登陆接口分析及SpringSecurity的登陆认证流程

一、登陆流程分析

0. 流程整理

在这里插入图片描述

1. 图片验证码接口/captchaImage

在这里插入图片描述

在登陆之前会有一个请求图片验证码的接口/captchaImage,页面获得图片验证码,后台接口生成一个图片和UUID,并将验证码Code和UUID存入的到Redis缓存中。
在这里插入图片描述

2.登陆验证接口/login

在这里插入图片描述

在这里插入图片描述

2.1 校验图片验证码

参数包括:登录名、密码、验证码、唯一标识,进行登录验证。
在这里插入图片描述

2.1 查询用户信息

如果验证码验证成功,则开始检验用户信息:会去调用 UserDetailsServiceImplloadUserByUsername方法。进行用户认证流程,具体见下一节。
在这里插入图片描述
在这里插入图片描述
UserDetailsServiceImpl是我们实现了UserDetailsService接口:
在这里插入图片描述
返回一个UserDetails对象,包括用户对象和用户的权限信息。

在这里插入图片描述

在这里插入图片描述
LoginUser实现了UserDetails
在这里插入图片描述

2.3查询用户的权限信息

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
sys_menu是菜单权限表,关联了角色-菜单关联表、用户-角色关联表、角色表。
也就是根据用户Id通过用户表-角色关联表 查询 角色信息,在通过角色-菜单表 查询菜单信息。
在这里插入图片描述

2.4 生成令牌token

在这里插入图片描述
先通过工具类生成一个UUID,作为令牌的唯一标识。

在这里插入图片描述

在这里插入图片描述

refreshToken()方法以生成的UUID加前缀作为Key,将用户信息存到缓存中,并设置有效期。

使用createToken方法生成 JWT 令牌

在这里插入图片描述
流程总结:
查询用户信息,生成UUID,以UUID作为key,用户信息为Value 存入缓存,在将UUID信息存放到到JWT令牌中,将令牌返回给前端页面。
用户再次请求的时候将令牌放到请求头中,后台解析令牌,获得UUID,去缓存中回去用户信息。

3.登录

登录成功:
在这里插入图片描述

二、SpringSecurity的登陆认证流程分析

在这里插入图片描述

1. AuthenticationManager 认证管理器

在这里插入图片描述
根据用户输入的用户名、密码构建了 UsernamePasswordAuthenticationToken,并将其交给 AuthenticationManager 来进行认证处理。AuthenticationManager 本身不包含认证逻辑,其核心是用来管理所有的 AuthenticationProvider,通过交由合适的 AuthenticationProvider 来实现认证。

2. ProviderManager

下面跳转到了 ProviderManager ,该类是 AuthenticationManager 的实现类。
在这里插入图片描述

3. AbstractUserDetailsAuthenticationProvider 查询UserDetails信息

传统表单登录的 AuthenticationProvider 主要是由 AbstractUserDetailsAuthenticationProvider 来进行处理的,通过 retrieveUser() 方法读取到数据库中的用户信息,具体实现在 DaoAuthenticationProvider

4. DaoAuthenticationProvider

在这里插入图片描述
在这里插入图片描述

5. UserDetailsService

这里调用了UserDetailsServiceloadUserByUsername方法,而我们的UserDetailsServiceImpl实现了UserDetailsService接口,重写了loadUserByUsername方法
在这里插入图片描述

6. AbstractUserDetailsAuthenticationProvider 进行认证

当我们成功的读取 UserDetails 后,下面开始对其进行认证。

在这里插入图片描述

6.1 认证前校验

在这里插入图片描述

6.2 附加校验

在这里插入图片描述

6.3 认证后校验

在这里插入图片描述

我们可以看到认证校验分为 前校验、附加校验和后校验,如果任何一个校验出错,就会抛出相应的异常。所有校验都通过后,调用 createSuccessAuthentication() 返回认证信息。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
createSuccessAuthentication 方法中,我们发现它重新 new 了一个 UsernamePasswordAuthenticationToken,因为到这里认证已经通过了,所以将 authorities 注入进去,并设置 authenticatedtrue
到此就已经认证完成了。

SpringSecurity认证流程文章参考:https://jitwxs.blog.csdn.net/article/details/84703690

三、在请求头中携带token信息请求后台接口

比如 登录后请求的/getInfo接口:
在这里插入图片描述
请求后台接口时,获取请求头中的认证信息:

Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImE5ZWQ4MjYxLTRmOTgtNDY1Zi1iNTcwLTlkMmU2MGEyOWQzOCJ9.z0gvgUQPDQSiMAm5QfljsRSPGkJhuCvjlA--m_Jd7y87QICeb53Sj28yMLxNQwkoXqwsk3HKLnkX1OjA5goUdQ

在这里插入图片描述

1. 获得请求头

首先使用ServletUtils.getRequest()获取request信息,这个方法有调用的是getRequestAttributes()方法,
在这里插入图片描述

在这里插入图片描述

2.获取请求头中的认证信息

获得了request信息后,从请求头中获取token:
在这里插入图片描述

3.解析jwt令牌,获取缓存中的用户信息

解析token,获取唯一标识,根据唯一标识获得缓存中的用户信息:
在这里插入图片描述

由此就获得了用户的信息,在根据用户信息查询对应的角色和权限。

  • 23
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
Spring Security和ElementUI可以很好地配合使用,实现前后端分离登录。 首先,你需要在Spring Boot中集成Spring Security。可以通过引入spring-boot-starter-security依赖来实现。在配置类中,你需要实现WebSecurityConfigurerAdapter,重写configure()方法,配置Spring Security的相关参数和行为。例如: ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private CustomUserDetailsService userDetailsService; @Autowired private JwtAuthenticationEntryPoint unauthorizedHandler; @Bean public JwtAuthenticationFilter jwtAuthenticationFilter() { return new JwtAuthenticationFilter(); } @Override public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception { authenticationManagerBuilder .userDetailsService(userDetailsService) .passwordEncoder(passwordEncoder()); } @Bean(BeanIds.AUTHENTICATION_MANAGER) @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { http .cors() .and() .csrf() .disable() .exceptionHandling() .authenticationEntryPoint(unauthorizedHandler) .and() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() .antMatchers("/api/auth/**") .permitAll() .anyRequest() .authenticated(); http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); } } ``` 在上述代码中,我们配置了自定义的用户认证服务(CustomUserDetailsService),密码加密方式(BCryptPasswordEncoder),JWT认证过滤器(JwtAuthenticationFilter),以及请求权限控制规则。 接下来,我们需要实现登录接口和JWT认证过滤器。具体实现可以参考下面代码: ```java @RestController @RequestMapping("/api/auth") public class AuthController { @Autowired private AuthenticationManager authenticationManager; @Autowired private JwtTokenProvider tokenProvider; @PostMapping("/login") public ResponseEntity<?> authenticateUser(@Valid @RequestBody LoginRequest loginRequest) { Authentication authentication = authenticationManager.authenticate( new UsernamePasswordAuthenticationToken( loginRequest.getUsernameOrEmail(), loginRequest.getPassword() ) ); SecurityContextHolder.getContext().setAuthentication(authentication); String jwt = tokenProvider.generateToken(authentication); return ResponseEntity.ok(new JwtAuthenticationResponse(jwt)); } } @Component public class JwtAuthenticationFilter extends OncePerRequestFilter { @Autowired private JwtTokenProvider tokenProvider; @Autowired private CustomUserDetailsService customUserDetailsService; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { try { String jwt = getJwtFromRequest(request); if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) { Long userId = tokenProvider.getUserIdFromJWT(jwt); UserDetails userDetails = customUserDetailsService.loadUserById(userId); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( userDetails, null, userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authentication); } } catch (Exception ex) { logger.error("Could not set user authentication in security context", ex); } filterChain.doFilter(request, response); } private String getJwtFromRequest(HttpServletRequest request) { String bearerToken = request.getHeader("Authorization"); if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { return bearerToken.substring(7); } return null; } } ``` 在上述代码中,我们实现了登录接口(AuthController),使用AuthenticationManager进行用户认证,使用JwtTokenProvider生成JWT token,并返回给客户端。 同时,我们实现了JWT认证过滤器(JwtAuthenticationFilter),在每个请求到达后端时,检查请求头中是否携带有效的JWT token,如果是,则将用户信息放入Spring Security上下文中,以便后续进行权限控制。 在ElementUI中,我们可以使用axios库发送登录请求,获取JWT token,并存储在localStorage中,以便后续请求时携带: ```javascript // 登录 axios.post('/api/auth/login', { usernameOrEmail: this.form.username, password: this.form.password }).then(response => { const token = response.data.accessToken localStorage.setItem('accessToken', token) axios.defaults.headers.common.Authorization = `Bearer ${token}` this.$router.push({ path: '/' }) }).catch(error => { console.log(error) }) ``` 在每个请求中,我们需要在请求头中添加Authorization字段,携带JWT token: ```javascript // 示例:获取用户列表 axios.get('/api/users', { headers: { Authorization: `Bearer ${localStorage.getItem('accessToken')}` } }).then(response => { console.log(response.data) }).catch(error => { console.log(error) }) ``` 以上就是如何使用Spring Security和ElementUI实现前后端分离登录的基本步骤。当然,具体实现还需要考虑更多细节和安全性问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Liu_Shihao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值