前后端分离的Web应用程序中使用Spring Security+Mybatis+JWT非对称加密+动态权限管理:身份验证过滤器

Posted wwwzgy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前后端分离的Web应用程序中使用Spring Security+Mybatis+JWT非对称加密+动态权限管理:身份验证过滤器相关的知识,希望对你有一定的参考价值。

在安全配置文件MySecurityConfig.java里配置了两个过滤器LoginFilter和JwtAuthenticationTokenFilter。

1、用户请求进来时,首先调用JwtAuthenticationTokenFilter过滤器,检查是否携带token,如果已有token,则验证token是否合法,如果合法,则直接通过验证。如果没有携带token,或者token不合法,则会进入下一个过滤器,即身份验证过滤器。以下是JwtAuthenticationTokenFilter过滤器代码:

package com.security;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import com.service.MyUserDetailsService;

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter{
    @Autowired
    MyUserDetailsService userDetailsService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {

        //请求头为 Authorization
        //请求体为 Bearer token
        String authHeader = request.getHeader("Authorization");  //获取请求头
        if (authHeader != null && authHeader.startsWith("Bearer ")) {  //如果请求头不为空,且以Bearer 开头

            final String authToken = authHeader.substring("Bearer ".length());  //获取令牌

            String username = JwtTokenUtils.parseToken(authToken);  //从令牌中获取用户名
            if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {  //如果用户认证信息不为空
                UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                if (userDetails != null) {
                    UsernamePasswordAuthenticationToken authentication =
                            new UsernamePasswordAuthenticationToken(userDetails, userDetails.getPassword(), userDetails.getAuthorities());
                    authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                }
            }
        }
        chain.doFilter(request, response);  //请求头为空,或重新认证不通过,则直接进入下一个过滤链
    }

}
View Code

2、用户第一次登录时(无token)或者token不合法时,将调用身份验证过滤器,即LoginFilter。

package com.security;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

public class LoginFilter extends UsernamePasswordAuthenticationFilter{
    String username;
    String password;
    
    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
            UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
                    username, password);
            setDetails(request, authRequest);
                return this.getAuthenticationManager().authenticate(authRequest);            
        
    }
}
View Code

身份验证主要是通过改写Authentication方法,通过以下3行代码即完成用户名和密码校验,这是标准的身份校验方法,切不可直接根据加密算法算出加密密文,然后再比较密文是否与数据库中的密文相同这样的方法。

UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);

 

以上是关于前后端分离的Web应用程序中使用Spring Security+Mybatis+JWT非对称加密+动态权限管理:身份验证过滤器的主要内容,如果未能解决你的问题,请参考以下文章

无意间做了个 web 版的 JVM 监控端(前后端分离 React+Spring Boot)

Keycloak快速上手指南,只需10分钟即可接入Spring Boot/Vue前后端分离应用实现S

WEB开发中前后端分离的好处与区别

Keycloak快速上手指南,只需10分钟即可接入Spring Boot/Vue前后端分离应用实现SSO单点登录

Keycloak快速上手指南,只需10分钟即可接入Spring Boot/Vue前后端分离应用实现SSO单点登录

基于Spring Boot架构的前后端完全分离项目API路径问题