SpringBoot整合Security

SpringBoot整合Security

pom

		<!-- security -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!-- jjwt -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
        </dependency>
        <!-- fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version>
        </dependency>
        <!-- commons-collections4 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-collections4</artifactId>
            <version>${commons-collections4.version}</version>
        </dependency>
        <!-- commons-long3 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>${commons-lang3.version}</version>
        </dependency>
        <!-- redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

代码

SecurityConfig
Security的配置类想生效的自定义配置类都在这里配置生效

import com.alibaba.fastjson.JSONObject;
import com.monitor.conf.profile.ConfigProfileValue;
import com.monitor.conf.redis.RedisUtil;
import com.monitor.conf.result.Result;
import com.monitor.conf.result.ResultCodeEnum;
import com.monitor.conf.security.Handler.CustomAccessDecisionManager;
import com.monitor.conf.security.Handler.CustomAuthenticationProvider;
import com.monitor.conf.security.Handler.CustomFilterInvocationSecurityMetadataSource;
import com.monitor.conf.security.Handler.CustomAuthenticationSuccessHandler;
import com.monitor.conf.security.filter.JwtAuthorizationTokenFilter;
import com.monitor.constants.BaseConstant;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

/**
 * @Author sm-liyujie
 * @Date 2023/6/1 17:44
 * @description: Security配置类
 * @Version 1.0
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 自定义登录成功处理器并生成token:响应状态码200及token
     */
    @Resource
    private CustomAuthenticationSuccessHandler authenticationSuccessHandler;

    /**
     * 自定义登录认证
     */
    @Resource
    private CustomAuthenticationProvider authenticationProvider;

    /**
     * 动态获取url权限配置
     */
    @Resource
    private CustomFilterInvocationSecurityMetadataSource filterInvocationSecurityMetadataSource;

    /**
     * 自定义权限判断管理器
     */
    @Resource
    private CustomAccessDecisionManager accessDecisionManager;

    /**
     * 身份验证详细信息源
     */
    @Resource
    private AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> authenticationDetailsSource;

    /**
     * JwtToken解析并生成authentication身份信息过滤器
     */
    @Resource
    private JwtAuthorizationTokenFilter authorizationTokenFilter;

    @Resource
    private RedisUtil redisUtil;


    @Override
    public void configure(WebSecurity web) {
        //无条件允许访问
//        web.ignoring().antMatchers("/command-record/getDiskResult");
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) {
        //自定义登录认证
        auth.authenticationProvider(authenticationProvider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        // 关闭csrf验证(防止跨站请求伪造攻击)
        http.csrf().disable();

        // JwtToken解析并生成authentication身份信息过滤器
        http.addFilterBefore(authorizationTokenFilter, UsernamePasswordAuthenticationFilter.class);

        // 未登录时:返回状态码401
        http.exceptionHandling().authenticationEntryPoint(jsonAuthenticationEntryPoint());

        // 无权访问时:返回状态码403
        http.exceptionHandling().accessDeniedHandler(jsonAccessDeniedHandler());

        // url权限认证处理
        http.antMatcher("/**").authorizeRequests()
//                .antMatchers("/security/user/**").hasRole("ADMIN") //需要ADMIN角色才可以访问
//                .antMatchers("/connect").hasIpAddress("127.0.0.1") //只有ip[127.0.0.1]可以访问'/connect'接口
                .anyRequest() //其他任何请求
                .authenticated() //都需要身份认证
                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O o) {
                        //动态获取url权限配置
                        o.setSecurityMetadataSource(filterInvocationSecurityMetadataSource);
                        //权限判断
                        o.setAccessDecisionManager(accessDecisionManager);
                        return o;
                    }
                });

        // 将session策略设置为无状态的,通过token进行登录认证
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        // 开启自动配置的登录功能
        http.formLogin()
                //自定义登录请求路径(post)
                .loginProcessingUrl("/nonceLogin")
                //自定义登录用户名密码属性名,默认为username和password
                .usernameParameter("username")
                .passwordParameter("password")
                //验证成功处理器(前后端分离):生成token及响应状态码200
                .successHandler(authenticationSuccessHandler)
                //验证失败处理器(前后端分离):返回状态码402
                .failureHandler(jsonAuthenticationFailureHandler())
                //登录验证中增加额外字段(验证码等等)
                .authenticationDetailsSource(authenticationDetailsSource);

        // 开启自动配置的注销功能
        http.logout()
                //自定义注销请求路径
                .logoutUrl("/nonceLogout")
                //注销成功处理器(前后端分离):返回状态码200
                .logoutSuccessHandler(jsonLogoutSuccessHandler());
    }

    /**
     * 自定义登录失败处理器:返回状态码402
     * @return
     */
    private AuthenticationFailureHandler jsonAuthenticationFailureHandler() {
        return (request, response, e) -> {
            response.setContentType("application/json;charset=utf-8");
            Result result = Result.builder()
                    .code("402")
                    .message(e.getMessage())
                    .build();
            response.setStatus(402);
            response.setCharacterEncoding("UTF-8");
            response.setContentType("text/html;charset=UTF-8");
            response.getWriter().write(JSONObject.toJSONString(result));
        };
    }

    /**
     * 自定义权限不足处理器:返回状态码403
     * @return
     */
    private AccessDeniedHandler jsonAccessDeniedHandler() {
        return (request, response, e) -> {
            response.setContentType("application/json;charset=utf-8");
            Result result = Result.builder()
                    .code("403")
                    .errorstack(e.getMessage())
                    .message("权限不足")
                    .build();
            response.setStatus(403);
            response.setCharacterEncoding("UTF-8");
            response.setContentType("text/html;charset=UTF-8");
            response.getWriter().write(JSONObject.toJSONString(result));
        };
    }

    /**
     * 自定义未登录时处理器:返回状态码401
     * @return
     */
    private AuthenticationEntryPoint jsonAuthenticationEntryPoint() {
        return (request, response, e) -> {
            response.setContentType("application/json;charset=utf-8");
            Result result = Result.builder()
                    .code("401")
                    .errorstack(e.getMessage())
                    .message("用户未登录")
                    .build();
            response.setStatus(401);
            response.setCharacterEncoding("UTF-8");
            response.setContentType("text/html;charset=UTF-8");
            response.getWriter().write(JSONObject.toJSONString(result));
        };
    }

    /**
     * 自定义注销成功处理器:返回状态码200
     * @return
     */
    private LogoutSuccessHandler jsonLogoutSuccessHandler() {
        return (request, response, e) -> {
            String token = request.getHeader(ConfigProfileValue.tokenHeaderKey);
            redisUtil.del(BaseConstant.REDIS_LOGIN_TOKEN_KEY + token);
            response.setContentType("application/json;charset=utf-8");
            Result result = Result.builder()
                    .code(ResultCodeEnum.SUCCESS.getCode())
                    .message("注销成功")
                    .build();

            response.setStatus(200);
            response.setCharacterEncoding("UTF-8");
            response.setContentType("text/html;charset=UTF-8");
            response.getWriter().write(JSONObject.toJSONString(result));
        };
    }
}

CustomAuthenticationProvider
自定义登录认证(判断账号密码,启用禁用等等)

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.monitor.conf.redis.RedisUtil;
import com.monitor.conf.security.server.CustomUserDetails;
import com.monitor.conf.security.server.CustomUserDetailsService;
import com.monitor.constants.BaseConstant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @Author sm-liyujie
 * @Date 2023/6/2 9:24
 * @description: 自定义登录认证
 * @Version 1.0
 */
@Component
@Slf4j
public class CustomAuthenticationProvider implements AuthenticationProvider {

    @Resource
    private CustomUserDetailsService userDetailsService;

    @Resource
    private RedisUtil redisUtil;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        log.info("authentication >> {}", JSONObject.toJSONString(authentication, SerializerFeature.WriteMapNullValue));
        //登录接口自定义字段(除了账号密码)
        CustomWebAuthenticationDetails customWebAuthenticationDetails = (CustomWebAuthenticationDetails) authentication.getDetails();
        //verifyCode测试字段(可以放验证码之类的信息)
        System.out.println("verifyCode >> " + customWebAuthenticationDetails.getVerifyCode());
        //表单输入的用户名
        String username = (String) authentication.getPrincipal();
        //表单输入的密码
        String password = (String) authentication.getCredentials();
        //根据Username获取用户
        CustomUserDetails userInfo = (CustomUserDetails) userDetailsService.loadUserByUsername(username);
        //校验用户名密码
        boolean matches = new BCryptPasswordEncoder().matches(password, userInfo.getPassword());
        if (!matches) {
            throw new BadCredentialsException("账号或密码错误");
        }
        if (!userInfo.isEnabled()) {
            throw new DisabledException("账号被禁用");
        }
        if (CollectionUtils.isEmpty(userInfo.getAuthorities())){
            throw new InsufficientAuthenticationException("用户无角色");
        }
        //存入redis 用户信息
        userInfo.setPassword(null);
        redisUtil.set(BaseConstant.USER_DETAILS_KEY + username,userInfo);
        //返回用户认证
        return new UsernamePasswordAuthenticationToken(username, userInfo.getPassword(), userInfo.getAuthorities());
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return true;
    }

}

CustomUserDetails
security的用户对象

import com.monitor.conf.result.BaseEntity;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;

/**
 * @Author sm-liyujie
 * @Date 2023/6/2 11:02
 * @description: security的用户对象
 * @Version 1.0
 */
@Data
public class CustomUserDetails extends BaseEntity implements UserDetails {

    /**
     * 用户名
     */
    private String username;

    /**
     * 昵称
     */
    private String nickName;

    /**
     * 密码
     */
    private String password;

    /**
     * 邮箱
     */
    private String email;

    /**
     * 手机号
     */
    private String phone;

    /**
     * 0禁用 1启用
     */
    private Integer enable;

    /**
     * 通过springSecurity进行授权
     */
    private Collection<? extends GrantedAuthority> authorities;

    private  Boolean enabled;
    private  Boolean accountNonExpired;
    private  Boolean credentialsNonExpired;
    private  Boolean accountNonLocked;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public String getUsername() {
        return username;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return enable == 1;
    }
}

CustomUserDetailsService
自定义用户认证,通过username去数据库获取用户并转化为CustomUserDetails

import com.monitor.modules.user.entity.model.SysUser;
import com.monitor.modules.user.service.SysUserService;
import com.monitor.utils.CopyUtil;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @Author sm-liyujie
 * @Date 2023/6/1 17:56
 * @description: 自定义用户认证
 * @Version 1.0
 */
@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Resource
    private SysUserService userService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //登录名获取用户(数据库)
        SysUser sysUser = userService.findUserByUserName(username);
        if (sysUser == null){
            throw new UsernameNotFoundException("User name" + username + "not find!!");
        }
        //对象拷贝
        CustomUserDetails userInfo = CopyUtil.copy(sysUser, CustomUserDetails.class);
        //用户角色集合
        Set<SimpleGrantedAuthority> authoritiesSet = new HashSet<>();
        //获取用户角色
        List<String> roles = userService.findRoleNameByUsername(sysUser.getId());
        for (String roleName : roles) {
            //用户拥有的角色
            SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(roleName);
            authoritiesSet.add(simpleGrantedAuthority);
        }
        userInfo.setAuthorities(authoritiesSet);
        return userInfo;
    }
}

CustomWebAuthenticationDetails
登录自定义字段

import org.springframework.security.web.authentication.WebAuthenticationDetails;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;

/**
 * @Author sm-liyujie
 * @Date 2023/6/2 9:38
 * @description: 登录自定义字段
 * @Version 1.0
 */
public class CustomWebAuthenticationDetails extends WebAuthenticationDetails implements Serializable {

    private String verifyCode;

    CustomWebAuthenticationDetails(HttpServletRequest httpServletRequest) {
        super(httpServletRequest);
        verifyCode = httpServletRequest.getParameter("verifyCode");
    }

    String getVerifyCode() {
        return verifyCode;
    }

}

CustomAuthenticationSuccessHandler
自定义登录成功处理器:返回状态码200

import com.alibaba.fastjson.JSONObject;
import com.monitor.conf.profile.ConfigProfileValue;
import com.monitor.conf.redis.RedisUtil;
import com.monitor.conf.result.Result;
import com.monitor.conf.result.ResultCodeEnum;
import com.monitor.conf.security.server.CustomUserDetails;
import com.monitor.constants.BaseConstant;
import com.monitor.utils.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author sm-liyujie
 * @Date 2023/6/2 9:23
 * @description: 自定义登录成功处理器:返回状态码200
 * @Version 1.0
 */
@Component
@Slf4j
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    @Resource
    private RedisUtil redisUtil;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {

        response.setCharacterEncoding("UTF-8");
        //这里也可以用map代替(返回的对象)
        Result result = Result.builder()
                .code(ResultCodeEnum.SUCCESS.getCode())
                .message("登录成功")
                .build();

        //表单输入的用户名
        String username = (String) authentication.getPrincipal();
        //用户角色
        List<String> role = authentication.getAuthorities()
                .stream()
                .map(GrantedAuthority::getAuthority)
                .collect(Collectors.toList());

        // 生成token并设置响应头
        Map<String,Object> claims = new HashMap<>();
        claims.put("username",username);
        claims.put("role", role);
        String token = JwtUtil.generate(username,claims);
        //存入redis token
        redisUtil.set(BaseConstant.REDIS_LOGIN_TOKEN_KEY + token, token, ConfigProfileValue.tokenExpiration);
        //设置token响应头
        response.addHeader(ConfigProfileValue.tokenHeaderKey, token);
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        response.getWriter().write(JSONObject.toJSONString(result));
    }

}

CustomFilterInvocationSecurityMetadataSource
动态获取url权限配置:将角色和权限进行绑定

import com.monitor.modules.user.service.SysRoleService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @Author sm-liyujie
 * @Date 2023/6/2 9:25
 * @description: 动态获取url权限配置
 * @Version 1.0
 */
@Component
@Slf4j
public class CustomFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    @Resource
    private SysRoleService roleService;

    @Override
    public Collection<ConfigAttribute> getAttributes(Object o) {

        Set<ConfigAttribute> set = new HashSet<>();
        // 获取请求地址
        String requestUrl = ((FilterInvocation) o).getRequestUrl();
        log.info("requestUrl >> {}", requestUrl);
        //获取接口需要的权限
        List<String> roleNames = roleService.findRoleNameByMenuUrl(requestUrl);
        if (CollectionUtils.isNotEmpty(roleNames)){
            //设置权限
            roleNames.forEach(roleName -> {
                        SecurityConfig securityConfig = new SecurityConfig(roleName);
                        set.add(securityConfig);
            });
        }
        //没有配置默认登录权限
        if (CollectionUtils.isEmpty(roleNames)) {
            return SecurityConfig.createList("ROLE_LOGIN");
        }
        return set;
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return FilterInvocation.class.isAssignableFrom(aClass);
    }
}

CustomAccessDecisionManager
自定义权限判断管理器:根据上面角色绑定的权限,看下当前登录用户有没有请求的接口需要的角色

import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;

import java.util.Collection;

/**
 * @Author sm-liyujie
 * @Date 2023/6/2 9:25
 * @description: 自定义权限判断管理器
 * @Version 1.0
 */
@Component
@Slf4j
public class CustomAccessDecisionManager implements AccessDecisionManager {

    @Override
    public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> collection) throws AccessDeniedException, InsufficientAuthenticationException {

        // 当前请求需要的权限
        log.info("collection:{}", collection);
        // 当前用户所具有的权限
        Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
        log.info("principal:{} authorities:{}", authentication.getPrincipal().toString(), authorities);

        for (ConfigAttribute configAttribute : collection) {
            // 当前请求需要的权限
            String needRole = configAttribute.getAttribute();
            if ("ROLE_LOGIN".equals(needRole)) {
                if (authentication instanceof AnonymousAuthenticationToken) {
                    throw new BadCredentialsException("Not logged in!!");
                } else {
                    return;
                }
            }
            // 当前用户所具有的权限
            for (GrantedAuthority grantedAuthority : authorities) {
                // 包含其中一个角色即可访问
                if (grantedAuthority.getAuthority().equals(needRole)) {
                    return;
                }
            }
        }
        throw new AccessDeniedException("SimpleGrantedAuthority!!");
    }

    @Override
    public boolean supports(ConfigAttribute configAttribute) {
        return true;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return true;
    }

}

JwtAuthorizationTokenFilter
JwtToken解析并生成authentication身份信息过滤器
拦截器验证token

import com.alibaba.fastjson.JSONObject;
import com.monitor.conf.profile.ConfigProfileValue;
import com.monitor.conf.redis.RedisUtil;
import com.monitor.conf.result.Result;
import com.monitor.constants.BaseConstant;
import com.monitor.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author sm-liyujie
 * @Date 2023/6/2 9:26
 * @description: JwtToken解析并生成authentication身份信息过滤器
 * @Version 1.0
 */
@Component
@Slf4j
public class JwtAuthorizationTokenFilter  extends OncePerRequestFilter {

    @Resource
    private RedisUtil redisUtil;

    /**
     * 解析token并生成authentication身份信息
     * @param request
     * @param response
     * @param chain
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException {
        try {
            String token = request.getHeader(ConfigProfileValue.tokenHeaderKey);
            log.info("JwtAuthorizationTokenFilter >> token:{}", token);
            //查看token是否存在
            String loginKey = BaseConstant.REDIS_LOGIN_TOKEN_KEY + token;
            String currentToken = (String) redisUtil.get(loginKey);
            if (null == token || !token.startsWith(ConfigProfileValue.tokenPrefix) || currentToken == null) {
                chain.doFilter(request, response);
                return;
            }
            // 解析token
            Claims claims = JwtUtil.getClaim(token);
            if (claims == null){
                chain.doFilter(request, response);
                return;
            }
            String username = (String) claims.get("username");
            List<String> roles = claims.get("role", List.class);
            List<SimpleGrantedAuthority> authorities = roles.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
            if (StringUtils.isNotEmpty(username)) {
                // 生成authentication身份信息
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, null, authorities);
                SecurityContextHolder.getContext().setAuthentication(authentication);
                //刷新token时间
                redisUtil.expire(loginKey,ConfigProfileValue.tokenExpiration);
            }
            chain.doFilter(request, response);
        } catch (Exception e) {
            log.error("token校验拦截器异常:" + e.getMessage());
            response.setContentType("application/json;charset=utf-8");
            Result result = Result.builder()
                    .code("500")
                    .message(e.getMessage())
                    .build();
            response.setStatus(500);
            response.setCharacterEncoding("UTF-8");
            response.setContentType("text/html;charset=UTF-8");
            response.getWriter().write(JSONObject.toJSONString(result));
        }
    }
}

数据库结构

-- ----------------------------
-- Table structure for sys_menu
-- ----------------------------
DROP TABLE IF EXISTS `sys_menu`;
CREATE TABLE `sys_menu`  (
  `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
  `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '请求路径',
  `menu_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '菜单名称',
  `parent_id` bigint NULL DEFAULT NULL COMMENT '父菜单id',
  `url_pre` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '路由(前端自己匹配用)',
  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
  `operator` bigint NOT NULL DEFAULT -1 COMMENT '操作人',
  `is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除:0是 1否',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role`  (
  `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
  `role_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色名称',
  `role_name_cn` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '角色名称中文',
  `role_desc` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '角色描述',
  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
  `operator` bigint NOT NULL DEFAULT -1 COMMENT '操作人',
  `is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除:0是 1否',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Table structure for sys_role_menu
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_menu`;
CREATE TABLE `sys_role_menu`  (
  `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
  `role_id` bigint NOT NULL COMMENT '角色id',
  `menu_id` bigint NOT NULL COMMENT '菜单id',
  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
  `operator` bigint NOT NULL DEFAULT -1 COMMENT '操作人',
  `is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除:0是 1否',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user`  (
  `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
  `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户名',
  `nick_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '昵称',
  `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '密码',
  `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱',
  `phone` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '手机号',
  `enable` tinyint(1) NOT NULL DEFAULT 1 COMMENT '0禁用 1启用',
  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
  `operator` bigint NOT NULL DEFAULT -1 COMMENT '操作人',
  `is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除:0是 1否',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Table structure for sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role`  (
  `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
  `user_id` bigint NOT NULL COMMENT '用户id',
  `role_id` bigint NOT NULL COMMENT '角色id',
  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
  `operator` bigint NOT NULL DEFAULT -1 COMMENT '操作人',
  `is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除:0是 1否',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值