Springboot+Security+Jwt

4 篇文章 1 订阅


工程目录

文章目录



前言

随着业务的发展,传统的不分离前后端的Java项目逐渐减少,更多的时候是做到前后端分离,会话管理也就从传统的Session会话管理变为Jwt管理会话,本篇文章就是SpringBoot使用Jwt管理会话同时整合Security,完成权限操作。


提示:以下是本篇文章正文内容,下面案例可供参考,可以按照工程目录进行拷贝搭建,希望对同行有所帮助!


一、Security是什么?

它是一个管理权限的框架,它包含了认证【即验证用户名密码】和授权【即用户可执行的操作】


二、使用步骤


1.引入pom.xml文件

代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.1.6.RELEASE</version>
  </parent>

  <groupId>Security_Jwt</groupId>
  <artifactId>Security_Jwt</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>Security_Jwt Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <maven.compiler.source>1.8</maven.compiler.source>
      <maven.compiler.target>1.8</maven.compiler.target>
      <junit.version>4.12</junit.version>
      <log4j.version>1.2.17</log4j.version>
      <lombok.version>1.14.8</lombok.version>
      <druid.version>1.1.16</druid.version>
      <commonslang.version>2.6</commonslang.version>
      <redis.version>2.1.3.RELEASE</redis.version>
      <springfox.version>2.7.0</springfox.version>
      <mybatis.plus.boot.starter.version>3.0.1</mybatis.plus.boot.starter.version>
      <pagehelper.spring.boot.starter.version>1.2.10</pagehelper.spring.boot.starter.version>
      <mysql-connector.version>5.1.39</mysql-connector.version>
  </properties>

  <dependencies>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency>
          <groupId>org.springframework.security</groupId>
          <artifactId>spring-security-taglibs</artifactId>
      </dependency>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-security</artifactId>
      </dependency>
      <dependency>
          <groupId>org.thymeleaf.extras</groupId>
          <artifactId>thymeleaf-extras-springsecurity5</artifactId>
      </dependency>

      <!-- JWT依赖 -->
      <dependency>
          <groupId>org.springframework.security</groupId>
          <artifactId>spring-security-jwt</artifactId>
      </dependency>
      <dependency>
          <groupId>io.jsonwebtoken</groupId>
          <artifactId>jjwt</artifactId>
          <version>0.9.0</version>
      </dependency>

      <!-- 引入 lombok -->
      <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
          <version>${lombok.version}</version>
      </dependency>

      <!-- swagger -->
      <dependency>
          <groupId>io.springfox</groupId>
          <artifactId>springfox-swagger2</artifactId>
          <version>${springfox.version}</version>
      </dependency>
      <dependency>
          <groupId>io.springfox</groupId>
          <artifactId>springfox-swagger-ui</artifactId>
          <version>${springfox.version}</version>
      </dependency>

      <!-- pagehelper分页 -->
      <dependency>
          <groupId>com.github.pagehelper</groupId>
          <artifactId>pagehelper-spring-boot-starter</artifactId>
          <version>${pagehelper.spring.boot.starter.version}</version>
      </dependency>

      <!-- mybatis-plus -->
      <dependency>
          <groupId>com.baomidou</groupId>
          <artifactId>mybatis-plus-boot-starter</artifactId>
          <version>${mybatis.plus.boot.starter.version}</version>
      </dependency>

      <!--mysql数据库依赖包-->
      <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>${mysql-connector.version}</version>
      </dependency>

      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-data-redis</artifactId>
          <version>${redis.version}</version>
      </dependency>

      <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>fastjson</artifactId>
          <version>1.2.70</version>
          <scope>compile</scope>
      </dependency>
      <dependency>
          <groupId>apache-lang</groupId>
          <artifactId>commons-lang</artifactId>
          <version>2.0</version>
      </dependency>


  </dependencies>

  <build>
    <finalName>Security_Jwt</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>


2.application.yml文件

代码如下:

server:
  port: 8080

#数据源
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/my_security_test?useUnicode=true&characterEncoding=UTF-8
    username: root
    password: root
#日期配置 yyyy-MM-dd HH:mm:ss
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss

#映射xml
mybatis-plus:
  mapper-locations: classpath:mapping/*.xml
  type-aliases-package: com.dev.model
  configuration:
#开启驼峰
    map-underscore-to-camel-case: true

#分页插件
pagehelper:
  auto-dialect: mysql
  reasonable: true
  support-methods-arguments: true

# JWT配置
jwt:
  # 密匙Key
  secret: limoumou
  # HeaderKey
  tokenHeader: Authorization
  # Token前缀
  tokenPrefix: Bearer
  # 过期时间,单位秒
  expiration: 86400
  # 配置白名单(不需要认证)
  antMatchers: /swagger-resources/**,/swagger-ui.html,/v2/api-docs,/webjars/**,/doc.html

3.启动类App8080.java

代码如下:

package com.dev;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @return {@link }
 * @throws
 * @author 李庆伟
 * @date 2021/7/14 14:41
 */
@SpringBootApplication
public class App8080 {
    public static void main(String[] args) {
        SpringApplication.run(App8080.class,args);
    }
}

4.Result.java

代码如下:

package com.dev.common;

import com.alibaba.fastjson.JSON;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import javax.servlet.ServletResponse;
import java.io.PrintWriter;
import java.util.List;

/**
 * @author 李庆伟
 * @date 2020/4/16 9:52
 */
@Data
public class Result {

    @ApiModelProperty(value = "返回码")
    private int code;

    @ApiModelProperty(value = "返回数据")
    private Object data;

    @ApiModelProperty(value = "返回描述")
    private String msg;

    @ApiModelProperty(value = "返回长度")
    private long count;

    /**返回成功 */
    public static Result success(List<Object> data, long count){
        Result result = new Result();
        result.setCode(0);//成功
        result.setMsg("成功");//提示语
        result.setData(data);
        result.setCount(count);
        return result;
    }

    /**返回成功 */
    public static Result success(List data){
        Result result = new Result();
        result.setCode(0);//成功
        result.setMsg("成功");//提示语
        result.setData(data);
        result.setCount(data == null || data.size() == 0 ? 0 : data.size());
        return result;
    }

    /**返回成功 */
    public static Result successForPage(List data,Integer count){
        Result result = new Result();
        result.setCode(0);//成功
        result.setMsg("成功");//提示语
        result.setData(data);
        result.setCount(count == null ? 0 : count);
        return result;
    }

    /**返回成功 */
    public static Result success(){
        Result result = new Result();
        result.setCode(0);//成功
        result.setMsg("成功");//提示语
        return result;
    }

    /**返回成功 */
    public static Result success(Object object){
        Result result = new Result();
        result.setCode(0);//成功
        result.setMsg("成功");//提示语
        result.setData(object);//返回内容
        return result;
    }

    /**返回失败 */
    public static Result error(){
        Result result = new Result();
        result.setCode(1);//失败
        result.setMsg("失败");//提示语
        return result;
    }

    /**返回失败 */
    public static Result error(int code, String msg){
        Result result = new Result();
        result.setCode(code);//失败
        result.setMsg(msg);//提示语
        return result;
    }

    /**返回信息*/
    public static Result response(int code, String msg, Object data) {
        Result result = new Result();
        result.setCode(code);
        result.setMsg(msg);
        result.setData(data);
        return result;
    }

    /**Response输出Json格式 */
    public static void responseJson(ServletResponse response, Object data) {
        PrintWriter out = null;
        try {
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json");
            out = response.getWriter();
            out.println(JSON.toJSONString(data));
            out.flush();
        } catch (Exception e) {
            System.out.println("Response输出Json异常:" + e);
        } finally {
            if (out != null) {
                out.close();
            }
        }
    }

}

5.MyException.java

代码如下:

package com.dev.config.exception;

/**
 * @author 李庆伟
 * @date 2020/4/16 10:10
 */
public class MyException extends RuntimeException{

    private int code;
    private String msg;

    public MyException(int code, String msg){
        super(msg);
        this.code = code;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

}

6.TopException

代码如下:

package com.dev.config.exception;

import com.dev.common.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @author 李庆伟
 * @date 2020/4/16 10:11
 */
@ControllerAdvice
public class TopException {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Result handle(Exception e){

        if(e instanceof MyException){
            logger.error("业务日志",e);
            MyException myException = (MyException) e;
            return  Result.error(myException.getCode(),myException.getMessage());
        }else if(e instanceof AccessDeniedException){
            return  Result.error(403,"访问权限不足");
        }

        logger.error("系统日志",e);
        return Result.error(1000,"业务繁忙");
    }
}

7.UserAccessDeniedHandler

代码如下:

package com.dev.config.security.handler;

import com.dev.common.Result;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 无权限处理类
 * @author 李庆伟
 * @date 2021/7/26 10:00
 */
@Component
public class UserAccessDeniedHandler implements AccessDeniedHandler {

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response,
                       AccessDeniedException accessDeniedException) throws IOException, ServletException {
        Result.responseJson(response, Result.response(403, "权限不足,拒绝访问", accessDeniedException.getMessage()));
    }

}

8.UserAuthenticationProvider

代码如下:

package com.dev.config.security.handler;

import com.dev.config.security.Md5Util;
import com.dev.model.SysUserDetails;
import com.dev.service.impl.SysUserDetailsService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

/**
 * @author 李庆伟
 * @date 2021/7/26 10:49
 */
@Component
public class UserAuthenticationProvider implements AuthenticationProvider {
    @Autowired
    private SysUserDetailsService userDetailsService;

    /**
     * 身份验证
     */
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = (String) authentication.getPrincipal(); // 获取用户名
        String password = (String) authentication.getCredentials(); // 获取密码
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
            throw new UsernameNotFoundException("用户名或密码不能为空");
        }
        if(username.equals("admin") && password.equals("123456")){
            SysUserDetails sysUserDetails = (SysUserDetails) userDetailsService.loadUserByUsername(username);
            return new UsernamePasswordAuthenticationToken(sysUserDetails, password, sysUserDetails.getAuthorities());
        } else if (username.equals("admin") && !password.equals("123456")){
            throw new BadCredentialsException("用户名或密码错误");
        } else {
            SysUserDetails sysUserDetails = (SysUserDetails) userDetailsService.loadUserByUsername(username);
            if (sysUserDetails == null) {
                throw new UsernameNotFoundException("用户名不存在");
            }
            if(!sysUserDetails.getPassword().equals(Md5Util.MD5(password))){
                throw new BadCredentialsException("用户名或密码错误");
            }
            return new UsernamePasswordAuthenticationToken(sysUserDetails, password, sysUserDetails.getAuthorities());
        }
    }

    /**
     * 支持指定的身份验证
     */
    @Override
    public boolean supports(Class<?> authentication) {
        return true;
    }

}

9.UserLoginFailureHandler

代码如下:

package com.dev.config.security.handler;

import com.dev.common.Result;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;

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

/**
 * 登录失败处理类
 * @author 李庆伟
 * @date 2021/7/26 10:03
 */
@Component
public class UserLoginFailureHandler implements AuthenticationFailureHandler {

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
                                        AuthenticationException exception) {
        Result.responseJson(response, Result.response(500, "登录失败", exception.getMessage()));
    }
}

10.UserLoginSuccessHandler

代码如下:

package com.dev.config.security.handler;

import com.dev.common.Result;
import com.dev.config.security.JWTTokenUtil;
import com.dev.model.SysUserDetails;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 * 登录成功处理类
 * @author 李庆伟
 * @date 2021/7/26 10:02
 */
@Component
public class UserLoginSuccessHandler implements AuthenticationSuccessHandler {

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                        Authentication authentication) {
        SysUserDetails sysUserDetails = (SysUserDetails) authentication.getPrincipal();
        String token = JWTTokenUtil.createAccessToken(sysUserDetails);
        Map<String, String> tokenMap = new HashMap<>();
        tokenMap.put("token", token);
        Result.responseJson(response, Result.response(0, "登录成功", tokenMap));
    }
}

11.UserLogoutSuccessHandler

代码如下:

package com.dev.config.security.handler;

import com.dev.common.Result;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;

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

/**
 * 登出成功处理类
 * @author 李庆伟
 * @date 2021/7/26 10:04
 */
@Component
public class UserLogoutSuccessHandler implements LogoutSuccessHandler {

    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
                                Authentication authentication) {
        SecurityContextHolder.clearContext();
        Result.responseJson(response, Result.response(200, "登出成功", null));
    }
}

12.UserNotLoginHandler

代码如下:

package com.dev.config.security.handler;

import com.dev.common.Result;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author 李庆伟
 * @date 2021/7/27 15:39
 */
@Component
public class UserNotLoginHandler implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response,
                         AuthenticationException authException) throws IOException, ServletException {
        Result.responseJson(response, Result.response(401, "未登录", authException.getMessage()));
    }
}

13.UserPermissionEvaluator

代码如下:

package com.dev.config.security.handler;

import com.dev.config.exception.MyException;
import com.dev.model.SysUserDetails;
import com.dev.model.TSysRes;
import com.dev.service.TSysResService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author 李庆伟
 * @date 2021/7/26 14:33
 */
@Configuration
@Component
public class UserPermissionEvaluator implements PermissionEvaluator {

    @Autowired
    private TSysResService tSysResService;

    /**
     * 判断是否拥有权限
     * [authentication, targetUrl, permission]
     * @return {@link boolean}
     * @throws
     * @author 李庆伟
     * @date 2021/12/7 19:42
     */
    @Override
    public boolean hasPermission(Authentication authentication, Object targetUrl, Object permission) {
        SysUserDetails sysUserDetails = null;
        try {
            sysUserDetails = (SysUserDetails) authentication.getPrincipal();
        } catch (Exception e){
            throw new MyException(403,"权限不足");
        }

        Set<String> permissions = new HashSet<String>(); // 用户权限

        List<TSysRes> authList = tSysResService.findResByUserId(sysUserDetails.getId());

        for (int i = 0; i < authList.size() ; i++) {
            permissions.add(authList.get(i).getPermission());
        }

        // 判断是否拥有权限
        if (permissions.contains(permission.toString())) {
            return true;
        }
        return false;
    }

    @Override
    public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType,
                                 Object permission) {
        return false;
    }

}

14.AutoSecurityConfig

代码如下:

package com.dev.config.security;

import com.dev.config.security.handler.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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.access.expression.DefaultWebSecurityExpressionHandler;

/**
 * @author 李庆伟
 * @date 2021/7/26 14:36
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // 开启方法权限注解
public class AutoSecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 无权限处理类
     */
    @Autowired
    private UserAccessDeniedHandler userAccessDeniedHandler;

    /**
     * 用户未登录处理类
     */
    @Autowired
    private UserNotLoginHandler userNotLoginHandler;

    /**
     * 用户登录成功处理类
     */
    @Autowired
    private UserLoginSuccessHandler userLoginSuccessHandler;

    /**
     * 用户登录失败处理类
     */
    @Autowired
    private UserLoginFailureHandler userLoginFailureHandler;

    /**
     * 用户登出成功处理类
     */
    @Autowired
    private UserLogoutSuccessHandler userLogoutSuccessHandler;

    /**
     * 用户登录验证
     */
    @Autowired
    private UserAuthenticationProvider userAuthenticationProvider;

    /**
     * 用户权限注解
     */
    @Autowired
    private UserPermissionEvaluator userPermissionEvaluator;

    /**
     * 加密方式,没使用这种加密方式
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 注入自定义PermissionEvaluator
     *
     * @return
     */
    @Bean
    public DefaultWebSecurityExpressionHandler userSecurityExpressionHandler() {
        DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
        handler.setPermissionEvaluator(userPermissionEvaluator);
        return handler;
    }

    /**
     * 用户登录验证
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(userAuthenticationProvider);
    }


    @Value("${jwt.antMatchers}")
    private String antMatchers;//白名单,这里是不做验证的方法
    /**
     * 安全权限配置
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests() // 权限配置
                .antMatchers(antMatchers.split(",")).permitAll()// 获取白名单(不进行权限验证)
                .anyRequest().authenticated() // 其他的需要登陆后才能访问
                .and().httpBasic().authenticationEntryPoint(userNotLoginHandler) // 配置未登录处理类
                .and().formLogin().loginProcessingUrl("/user/login")// 配置登录URL
                //.and().formLogin().loginPage("/user/login")// 配置登录URL
                .successHandler(userLoginSuccessHandler) // 配置登录成功处理类
                .failureHandler(userLoginFailureHandler) // 配置登录失败处理类
                .and().logout().logoutUrl("/logout/submit")// 配置登出地址
                .logoutSuccessHandler(userLogoutSuccessHandler) // 配置用户登出处理类
                .and().logout()   //退出登录相关配置
                      .logoutSuccessUrl("/page/index") //退出成功后跳转的页面
                      .deleteCookies("JSESSIONID")    //退出时要删除的Cookies的名字
                .and().exceptionHandling().accessDeniedHandler(userAccessDeniedHandler)// 配置没有权限处理类
                .and().cors()// 开启跨域
                .and().csrf().disable(); // 禁用跨站请求伪造防护
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); // 禁用session(使用Token认证)
        http.headers().cacheControl(); // 禁用缓存
        http.addFilter(new JWTAuthenticationFilter(authenticationManager()));  添加JWT过滤器
    }

}

15.JWTAuthenticationFilter

代码如下:

package com.dev.config.security;

import com.dev.model.SysUserDetails;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author 李庆伟
 * @date 2021/7/26 10:52
 */
public class JWTAuthenticationFilter extends BasicAuthenticationFilter {

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws IOException, ServletException {
        // 取出Token
        String token = request.getHeader(JWTConfig.tokenHeader);

        if (token != null && token.startsWith(JWTConfig.tokenPrefix)) {
            SysUserDetails sysUserDetails = JWTTokenUtil.parseAccessToken(token);

            if (sysUserDetails != null) {
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                        sysUserDetails, sysUserDetails.getId(), sysUserDetails.getAuthorities());
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        }
        filterChain.doFilter(request, response);
    }

}

16.JWTConfig

代码如下:

package com.dev.config.security;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * @author 李庆伟
 * @date 2021/7/26 9:54
 */
@Component
@ConfigurationProperties(prefix = "jwt")
public class JWTConfig {

    /**
     * 密匙Key
     */
    public static String secret;

    /**
     * HeaderKey
     */
    public static String tokenHeader;

    /**
     * Token前缀
     */
    public static String tokenPrefix;

    /**
     * 过期时间
     */
    public static Integer expiration;

    /**
     * 配置白名单
     */
    public static String antMatchers;

    /**
     * 将过期时间单位换算成毫秒
     *
     * @param expiration 过期时间,单位秒
     */
    public void setExpiration(Integer expiration) {
        this.expiration = expiration * 1000;
    }

    public void setSecret(String secret) {
        this.secret = secret;
    }

    public void setTokenHeader(String tokenHeader) {
        this.tokenHeader = tokenHeader;
    }

    public void setTokenPrefix(String tokenPrefix) {
        this.tokenPrefix = tokenPrefix + " ";
    }

    public void setAntMatchers(String antMatchers) {
        this.antMatchers = antMatchers;
    }

}

17.JWTTokenUtil

代码如下:

package com.dev.config.security;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.dev.model.SysUserDetails;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

import java.util.*;

/**
 * @author 李庆伟
 * @date 2021/7/26 9:57
 */
@Slf4j
public class JWTTokenUtil {

    /**
     * 创建Token
     *
     * @param sysUserDetails 用户信息
     * @return
     */
    public static String createAccessToken(SysUserDetails sysUserDetails) {
        String token = Jwts.builder().setId(// 设置JWT
                sysUserDetails.getId()) // 用户Id
                .setSubject(sysUserDetails.getUsername()) // 主题
                .setIssuedAt(new Date()) // 签发时间
                .setIssuer("limoumou") // 签发者
                .setExpiration(new Date(System.currentTimeMillis() + JWTConfig.expiration)) // 过期时间
                .signWith(SignatureAlgorithm.HS512, JWTConfig.secret) // 签名算法、密钥
                .claim("authorities", JSON.toJSONString(sysUserDetails.getAuthorities())).compact(); // 自定义其他属性,如用户组织机构ID,用户所拥有的角色,用户权限信息等
        return JWTConfig.tokenPrefix + token;
    }

    /**
     * 解析Token
     *
     * @param token Token信息
     * @return
     */
    public static SysUserDetails parseAccessToken(String token) {
        SysUserDetails sysUserDetails = null;
        if (StringUtils.isNotEmpty(token)) {
            try {
                // 去除JWT前缀
                token = token.substring(JWTConfig.tokenPrefix.length());

                // 解析Token
                Claims claims = Jwts.parser().setSigningKey(JWTConfig.secret).parseClaimsJws(token).getBody();

                // 获取用户信息
                sysUserDetails = new SysUserDetails();
                sysUserDetails.setId(claims.getId());
                sysUserDetails.setUsername(claims.getSubject());
                // 获取角色
                Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
                String authority = claims.get("authorities").toString();
                if (StringUtils.isNotEmpty(authority)) {
                    List<Map<String, String>> authorityList = JSON.parseObject(authority,
                            new TypeReference<List<Map<String, String>>>() {
                            });
                    for (Map<String, String> role : authorityList) {
                        if (!role.isEmpty()) {
                            authorities.add(new SimpleGrantedAuthority(role.get("authority")));
                        }
                    }
                }
                sysUserDetails.setAuthorities(authorities);
            } catch (Exception e) {
                log.error("解析Token异常:" + e);
            }
        }
        return sysUserDetails;
    }

}

18.Md5Util

代码如下:

package com.dev.config.security;

import java.security.MessageDigest;

/**
 * @author 李庆伟
 * @date 2021/7/28 15:54
 */
public class Md5Util {

    public final static String MD5(String s) {
        char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
        try {
            // 密码+盐组合
            byte[] btInput = s.getBytes();
            // 获得MD5摘要算法的 MessageDigest 对象
            MessageDigest mdInst = MessageDigest.getInstance("MD5");
            // 使用指定的字节更新摘要
            mdInst.update(btInput);
            // 获得密文
            byte[] md = mdInst.digest();
            // 把密文转换成十六进制的字符串形式
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 测试
     * [args]
     * @throws
     * @author 李庆伟
     * @date 2021/12/13 19:38
     */
    public static void main(String[] args) {
        String pwd = Md5Util.MD5("123456");
        System.out.println(pwd );
    }
}

19.SwaggerConfig

代码如下:

package com.dev.config;

import com.dev.App8080;
import com.fasterxml.classmate.TypeResolver;
import com.google.common.collect.Sets;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.OperationBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiDescription;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.ApiListingScannerPlugin;
import springfox.documentation.spi.service.contexts.DocumentationContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.spring.web.readers.operation.CachingOperationNameGenerator;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 接口文档配置
 * @return {@link }
 * @throws
 * @author 李庆伟
 * @date 2021/7/19 17:15
 */
@ConditionalOnWebApplication
@Configuration
@EnableSwagger2
public class SwaggerConfig implements ApiListingScannerPlugin {

    /**
     * Swagger2的配置文件,这里可以配置Swagger2的一些基本的内容,比如扫描的包等等
     * []
     * @return {@link Docket}
     * @throws
     * @author 李庆伟
     * @date 2021/12/13 16:28
     */
    @Bean
    public Docket createRestApi() {

        List<Parameter> pars = new ArrayList<>();
        ParameterBuilder token = new ParameterBuilder();
        token.name("Authorization").description("Authorization")
                .modelRef(new ModelRef("string"))
                .parameterType("header")
                .required(false).build();
        pars.add(token.build());

        ParameterBuilder languageCode = new ParameterBuilder();
        languageCode.name("languageCode").description("languageCode")
                .modelRef(new ModelRef("string"))
                .parameterType("header")
                .required(false).build();
        pars.add(languageCode.build());

        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.basePackage(App8080.class.getPackage().getName()))
                .build()
                .globalOperationParameters(pars)
                .apiInfo(apiInfo());

    }

    /**
     * 构建API文档的详细信息函数
     * @return
     */
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("项目接口 API")
                .version("1.0")
                .build();
    }


    /**
     * Security指定的登录接口不会出现在swagger中,为了方便可以自定义登录接口在swagger中。
     * [documentationContext]
     * @return {@link List<ApiDescription>}
     * @throws
     * @author 李庆伟
     * @date 2021/12/13 16:20
     */
    @Override
    public List<ApiDescription> apply(DocumentationContext documentationContext) {
        return new ArrayList<ApiDescription>(
                Arrays.asList(
                        new ApiDescription(
                                "/user/login",  //url
                                "登录", //描述
                                Arrays.asList(
                                        new OperationBuilder(
                                                new CachingOperationNameGenerator())
                                                .method(HttpMethod.POST)//http请求类型
                                                .produces(Sets.newHashSet(MediaType.APPLICATION_JSON_VALUE))
                                                .summary("登录")
                                                .notes("登录")//方法描述
                                                .tags(Sets.newHashSet("登录"))//归类标签
                                                .parameters(
                                                        Arrays.asList(
                                                                new ParameterBuilder()
                                                                        .description("用户名")
                                                                        .type(new TypeResolver().resolve(String.class))
                                                                        .name("username")
                                                                        .parameterType("query")
                                                                        .parameterAccess("access")
                                                                        .required(true)
                                                                        .modelRef(new ModelRef("string")) //<5>
                                                                        .build(),
                                                                new ParameterBuilder()
                                                                        .description("密码")
                                                                        .type(new TypeResolver().resolve(String.class))
                                                                        .name("password")
                                                                        .parameterType("query")
                                                                        .parameterAccess("access")
                                                                        .required(true)
                                                                        .modelRef(new ModelRef("string")) //<5>
                                                                        .build()
                                                        ))
                                                .build()),
                                false)));
    }

    @Override
    public boolean supports(DocumentationType documentationType) {
        return DocumentationType.SWAGGER_2.equals(documentationType);
    }
}

20.TSysUserController

代码如下:

package com.dev.controller;

import com.dev.common.Result;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;


/**
 * 系统用户服务
 * @author 李庆伟
 * @date 2021/7/19 17:04
 */
@Slf4j
@RequestMapping("tSysUser")
@RestController
@Api(value = "系统用户服务", tags = "系统用户服务")
public class TSysUserController {

    @PreAuthorize("hasRole('ROLE_/tSysUser/findByPage')")
    @PostMapping("findByPage")
    @ApiOperation(value = "添加系统用户", notes = "添加系统用户", produces = "application/json")
    public Result findByPage(){
        log.info("测试用户分页查询权限");
        return Result.success("测试用户分页查询权限");
    }

    @PreAuthorize("hasRole('ROLE_/tSysUser/add')")
    @PostMapping("add")
    @ApiOperation(value = "添加系统用户", notes = "添加系统用户", produces = "application/json")
    public Result add(){
        log.info("测试用户添加权限");
        return Result.success("测试用户添加权限");
    }

    @PreAuthorize("hasRole('ROLE_/tSysUser/edit')")
    @PostMapping("edit")
    @ApiOperation(value = "修改系统用户", notes = "修改系统用户", produces = "application/json")
    public Result edit(){
        log.info("测试用户编辑权限");
        return Result.success("测试用户编辑权限");
    }

    @PreAuthorize("hasRole('ROLE_/tSysUser/delete')")
    @PostMapping("delete")
    @ApiOperation(value = "删除系统用户", notes = "删除系统用户", produces = "application/json")
    public Result delete(){
        log.info("测试用户删除权限");
        return Result.success("测试用户删除权限");
    }
}

21.TSysResMapper

代码如下:

package com.dev.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dev.model.TSysRes;
import org.apache.ibatis.annotations.Mapper;



/**
 * @author 李庆伟
 * @date 2021/7/19 17:06
 */
@Mapper
public interface TSysResMapper extends BaseMapper<TSysRes> {


}

22.TSysRoleMapper

代码如下:

package com.dev.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dev.model.TSysRole;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
 * @author 李庆伟
 * @date 2021/7/19 17:06
 */
@Mapper
public interface TSysRoleMapper extends BaseMapper<TSysRole> {

    /**
     * 根据用户名查询用户有的角色
     * [userId]
     * @return {@link List<TSysRole>}
     * @throws
     * @author 李庆伟
     * @date 2021/7/27 14:40
     */
    @Select("SELECT r.* FROM t_sys_role r " +
            "LEFT JOIN t_sys_user_role ur ON ur.role_id = r.id " +
            "WHERE " +
            "ur.user_id = #{userId} ")
    List<TSysRole> findRoleByUserId(String userId);


}

23.TSysRoleResMapper

代码如下:

package com.dev.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dev.model.TSysRoleRes;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;
import java.util.Map;

/**
 * @author 李庆伟
 * @date 2021/7/19 17:06
 */
@Mapper
public interface TSysRoleResMapper extends BaseMapper<TSysRoleRes> {

    List<String> selectRoleResByMap(Map<String, Object> map);
    
}

24.TSysUserMapper

代码如下:

package com.dev.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dev.model.TSysUser;
import org.apache.ibatis.annotations.Mapper;

/**
 * @author 李庆伟
 * @date 2021/7/19 17:06
 */
@Mapper
public interface TSysUserMapper extends BaseMapper<TSysUser> {


}

25.TSysUserRoleMapper

代码如下:

package com.dev.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dev.model.TSysUserRole;
import org.apache.ibatis.annotations.Mapper;

/**
 * @author 李庆伟
 * @date 2021/7/19 17:06
 */
@Mapper
public interface TSysUserRoleMapper extends BaseMapper<TSysUserRole> {


}

26.SysUserDetails

代码如下:

package com.dev.model;

import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.io.Serializable;
import java.util.Collection;

/**
 * @author 李庆伟
 * @date 2021/7/26 9:48
 */
@Data
@EqualsAndHashCode(callSuper = false)
public class SysUserDetails extends TSysUser implements UserDetails, Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 用户角色
     */
    private Collection <GrantedAuthority> authorities;

    /**
     * 账号是否过期
     */
    private boolean isAccountNonExpired = false;

    /**
     * 账号是否锁定
     */
    private boolean isAccountNonLocked = false;

    /**
     * 证书是否过期
     */
    private boolean isCredentialsNonExpired = false;

    /**
     * 账号是否有效
     */
    private boolean isEnabled = true;

    /**
     * 获得用户权限
     */
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }

    /**
     * 判断账号是否过期
     */
    @Override
    public boolean isAccountNonExpired() {
        return isAccountNonExpired;
    }

    /**
     * 判断账号是否锁定
     */
    @Override
    public boolean isAccountNonLocked() {
        return isAccountNonLocked;
    }

    /**
     * 判断证书是否过期
     */
    @Override
    public boolean isCredentialsNonExpired() {
        return isCredentialsNonExpired;
    }

    /**
     * 判断账号是否有效
     */
    @Override
    public boolean isEnabled() {
        return isEnabled;
    }

}

27.TSysRes

代码如下:

package com.dev.model;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.util.Date;

/**
 * 系统资源实体
 * @return {@link }
 * @throws
 * @author 李庆伟
 * @date 2021/7/22 9:25
 */
@Data
@TableName("t_sys_res")
public class TSysRes {

    @TableId
    private String id;//主键
    private String name;//资源名称
    private String resUrl;//资源路径
    private String permission;//做拦截的code
    private String resType;//0菜单   1按钮
    private String pid;//父级id
    private String icon;//菜单图标
    private String createUser;//创建人
    private Date createDate;//创建时间

}

28.TSysRole

代码如下:

package com.dev.model;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.util.Date;

/**
 * 系统角色实体
 * @author 李庆伟
 * @date 2021/7/19 17:00
 */
@Data
@TableName("t_sys_role")
public class TSysRole {

    @TableId
    private String id;//主键
    private String roleName;//角色名称
    private String roleExplain;//角色描述
    private String createUser;//创建人
    private Date createDate;//创建时间

}

29.TSysRoleRes

代码如下:

package com.dev.model;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;


/**
 * 系统角色资源实体
 * @author 李庆伟
 * @date 2021/7/19 17:00
 */
@Data
@TableName("t_sys_role_res")
public class TSysRoleRes {

    @TableId
    private String id;//主键
    private String roleId;//角色id
    private String resId;//资源id

}

30.TSysUser

代码如下:

package com.dev.model;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 系统用户实体
 * @author 李庆伟
 * @date 2021/7/19 17:00
 */
@Data
@TableName("t_sys_user")
public class TSysUser implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId
    private String id;//主键
    private String username;//用户名
    private String password;//密码
    private String nickName;//昵称
    private String cellPhone;//电话
    private String mail;//邮件
    private Date birthday;//生日
    private String status;//状态(0-正常,1-禁用,2-删除)
    private String accountType;//1系统账号 2客户账号
    private String inviteCode;//邀请码
    private String sex;//性别:0男 1女
    private String address;//地址
    private Integer upNum;//获赞总量
    private Integer readNum;//文章被阅读总量
    private String sign;//签名
    private String pictureId;//用户头像
    private String createUser;//创建人
    private Date createDate;//创建时间

}

31.TSysUserRole

代码如下:

package com.dev.model;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
 * 系统用户角色实体
 * @author 李庆伟
 * @date 2021/7/19 17:00
 */
@Data
@TableName("t_sys_user_role")
public class TSysUserRole {

    @TableId
    private String id;//主键
    private String userId;//用户名id
    private String roleId;//角色id
}

32.SysUserDetailsService

代码如下:

package com.dev.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dev.model.SysUserDetails;
import com.dev.model.TSysRes;
import com.dev.model.TSysUser;
import com.dev.dao.TSysResMapper;
import com.dev.service.TSysResService;
import com.dev.service.TSysUserService;
import com.github.pagehelper.util.StringUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
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 李庆伟
 * @date 2021/7/26 10:44
 */
@Service
public class SysUserDetailsService  implements UserDetailsService {

    @Autowired
    private TSysUserService tSysUserService;

    @Resource
    private TSysResMapper tSysResMapper;

    @Autowired
    private TSysResService tSysResService;

    /**
     * 说明:重写UserDetailsService中的loadUserByUsername,就是查询用户详细信息封装到 UserDetails
     * 业务:
     *      ①如果是admin会拥有全部权限
     *      ②如果不是admin就去查用户信息和用户拥有的权限
     * [username]
     * @return {@link UserDetails}
     * @throws
     * @author 李庆伟
     * @date 2021/12/7 19:49
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        List<TSysRes> resList = null;
        if(username.equals("admin")){
            TSysUser tSysUser = new TSysUser();
            tSysUser.setId("admin");
            tSysUser.setUsername("admin");
            tSysUser.setNickName("系统管理员");
            SysUserDetails sysUserDetails = new SysUserDetails();
            BeanUtils.copyProperties(tSysUser, sysUserDetails);
            Set<GrantedAuthority> authorities = new HashSet<>(); // 角色集合

            //admin用户有的资源集合
            resList = tSysResMapper.selectList(new QueryWrapper<>());
            for (int i = 0; i < resList.size() ; i++) {
                if(StringUtil.isNotEmpty(resList.get(i).getPermission())){
                    authorities.add(new SimpleGrantedAuthority("ROLE_" + resList.get(i).getPermission()));
                }
            }
            sysUserDetails.setAuthorities(authorities);
            return sysUserDetails;
        }
        TSysUser tSysUser = tSysUserService.findByUsername(username);
        if (tSysUser != null) {
            SysUserDetails sysUserDetails = new SysUserDetails();
            BeanUtils.copyProperties(tSysUser, sysUserDetails);

            Set<GrantedAuthority> authorities = new HashSet<>(); // 角色集合

            resList = tSysResService.findResByUserId(sysUserDetails.getId());//当前用户有的资源集合
            if(resList != null){
                for (int i = 0; i < resList.size() ; i++) {
                    if(StringUtil.isNotEmpty(resList.get(i).getPermission())){
                        authorities.add(new SimpleGrantedAuthority("ROLE_" + resList.get(i).getPermission()));
                    }
                }
            }
            sysUserDetails.setAuthorities(authorities);
            return sysUserDetails;
        }
        return null;
    }
}

33.TSysResServiceImpl

代码如下:

package com.dev.service.impl;

import com.dev.model.TSysRes;
import com.dev.model.TSysRole;
import com.dev.dao.TSysResMapper;
import com.dev.dao.TSysRoleMapper;
import com.dev.dao.TSysRoleResMapper;
import com.dev.service.TSysResService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 系统角色服务
 * @author 李庆伟
 * @date 2021/7/19 17:06
 */
@Service
public class TSysResServiceImpl implements TSysResService {

    @Resource
    private TSysResMapper tSysResMapper;

    @Resource
    private TSysRoleMapper tSysRoleMapper;

    @Resource
    private TSysRoleResMapper tSysRoleResMapper;
    /**
     * 根据用户id查询用户拥有的资源
     * [userId]
     * @return {@link List< TSysRes>}
     * @throws
     * @author 李庆伟
     * @date 2021/12/7 20:34
     */
    @Override
    public List<TSysRes> findResByUserId(String userId) {
        //获取用户有的角色
        //根据当前登录用户获取角色
        List<TSysRole> roleList = tSysRoleMapper.findRoleByUserId(userId);
        if(roleList == null || roleList.size() == 0){ //如果用户没有角色返回没有权限
            return null;
        }
        //根据角色获取菜单资源id关系集合
        Map<String,Object> map = new HashMap<>();
        map.put("roleList",roleList);
        List<String> tSysRoleResList = tSysRoleResMapper.selectRoleResByMap(map);
        if(tSysRoleResList == null || tSysRoleResList.size() == 0){ //如果用户没有角色返回没有权限
            return null;
        }
        //根据资源id获取菜单资源
        return tSysResMapper.selectBatchIds(tSysRoleResList);

    }

}

34.TSysRoleResServiceImpl

代码如下:

package com.dev.service.impl;

import com.dev.service.TSysRoleResService;
import org.springframework.stereotype.Service;



/**
 * 系统角色资源服务
 * @author 李庆伟
 * @date 2021/7/19 17:06
 */
@Service
public class TSysRoleResServiceImpl implements TSysRoleResService {

}

35.TSysRoleServiceImpl

代码如下:

package com.dev.service.impl;

import com.dev.service.TSysRoleService;
import org.springframework.stereotype.Service;



/**
 * 系统角色服务
 * @author 李庆伟
 * @date 2021/7/19 17:06
 */
@Service
public class TSysRoleServiceImpl implements TSysRoleService {


}

36.TSysUserRoleServiceImpl

代码如下:

package com.dev.service.impl;

import com.dev.service.TSysUserRoleService;
import org.springframework.stereotype.Service;



/**
 * 系统用户角色服务
 * @author 李庆伟
 * @date 2021/7/19 17:06
 */
@Service
public class TSysUserRoleServiceImpl implements TSysUserRoleService {


}

37.TSysUserServiceImpl

代码如下:

package com.dev.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dev.model.TSysUser;
import com.dev.dao.TSysUserMapper;
import com.dev.service.TSysUserService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * 系统用户服务
 * @author 李庆伟
 * @date 2021/7/19 17:06
 */
@Service
public class TSysUserServiceImpl implements TSysUserService {


    @Resource
    private TSysUserMapper tSysUserMapper;


    /**
     * 根据用户名查询用户
     * [username]
     * @return {@link TSysUser}
     * @throws
     * @author 李庆伟
     * @date 2021/7/27 11:11
     */
    public TSysUser findByUsername(String username) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("username",username);
        return tSysUserMapper.selectOne(queryWrapper);
    }


}

38.TSysResService

代码如下:

package com.dev.service;

import com.dev.model.TSysRes;

import java.util.List;

/**
 * @author 李庆伟
 * @date 2021/7/19 17:05
 */
public interface TSysResService {

    List<TSysRes> findResByUserId(String userId);

}

39.TSysRoleResService

代码如下:

package com.dev.service;




/**
 * @author 李庆伟
 * @date 2021/7/19 17:05
 */
public interface TSysRoleResService {


}

40.TSysRoleService

代码如下:

package com.dev.service;


/**
 * @author 李庆伟
 * @date 2021/7/19 17:05
 */
public interface TSysRoleService {


}

41.TSysUserRoleService

代码如下:

package com.dev.service;




/**
 * @author 李庆伟
 * @date 2021/7/19 17:05
 */
public interface TSysUserRoleService {

}

42.TSysUserServiceImpl

代码如下:

package com.dev.service;


import com.dev.model.TSysUser;

/**
 * @author 李庆伟
 * @date 2021/7/19 17:05
 */
public interface TSysUserService {

    TSysUser findByUsername(String username);

}



库表【跟上篇文章的一样】:

 

 导入数据库sql

/*
 Navicat Premium Data Transfer

 Source Server         : 本机数据库mysql
 Source Server Type    : MySQL
 Source Server Version : 50143
 Source Host           : localhost:3306
 Source Schema         : my_security_test

 Target Server Type    : MySQL
 Target Server Version : 50143
 File Encoding         : 65001

 Date: 08/12/2021 21:17:27
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for t_sys_res
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_res`;
CREATE TABLE `t_sys_res`  (
  `id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '资源id',
  `name` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '资源名称',
  `res_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '资源路径',
  `permission` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '资源code',
  `res_type` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '0菜单   1按钮',
  `pid` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '父级id',
  `create_user` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  `create_date` datetime DEFAULT NULL,
  `icon` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '菜单图标'
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-资源表【菜单】' ROW_FORMAT = Compact;

-- ----------------------------
-- Records of t_sys_res
-- ----------------------------
INSERT INTO `t_sys_res` VALUES ('101', '用户添加', '/tSysUser/add', '/tSysUser/add', '1', '100', NULL, NULL, '');
INSERT INTO `t_sys_res` VALUES ('100', '用户管理', '/tSysUser/findByPage', '/tSysUser/findByPage', '0', '', NULL, NULL, 'fa fa-snowflake-o');
INSERT INTO `t_sys_res` VALUES ('102', '用户修改', '/tSysUser/edit', '/tSysUser/edit', '1', '100', NULL, NULL, 'fa fa-home');
INSERT INTO `t_sys_res` VALUES ('103', '用户删除', '/tSysUser/delete', '/tSysUser/delete', '1', '100', NULL, NULL, 'fa fa-home');

-- ----------------------------
-- Table structure for t_sys_role
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_role`;
CREATE TABLE `t_sys_role`  (
  `id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色id',
  `role_name` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色名称',
  `role_explain` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '描述',
  `create_user` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '创建人',
  `create_date` datetime DEFAULT NULL COMMENT '创建时间'
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-角色表' ROW_FORMAT = Compact;

-- ----------------------------
-- Records of t_sys_role
-- ----------------------------
INSERT INTO `t_sys_role` VALUES ('277144172094291968', '部门经理', '部门经理', NULL, '2021-08-27 10:22:51');
INSERT INTO `t_sys_role` VALUES ('277144675716956160', '普通员工', '普通员工', NULL, '2021-08-27 10:24:51');
INSERT INTO `t_sys_role` VALUES ('277646459757658112', '测试员工', '测试员工', '', '2021-08-28 19:38:46');

-- ----------------------------
-- Table structure for t_sys_role_res
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_role_res`;
CREATE TABLE `t_sys_role_res`  (
  `id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '主键',
  `role_id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色id',
  `res_id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '资源id'
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-角色资源表中间表' ROW_FORMAT = Compact;

-- ----------------------------
-- Records of t_sys_role_res
-- ----------------------------
INSERT INTO `t_sys_role_res` VALUES ('1234', '277144675716956160', '101');
INSERT INTO `t_sys_role_res` VALUES ('12345', '277144675716956160', '100');
INSERT INTO `t_sys_role_res` VALUES ('123456', '277144172094291968', '100');
INSERT INTO `t_sys_role_res` VALUES ('123457', '277144172094291968', '101');
INSERT INTO `t_sys_role_res` VALUES ('123458', '277144172094291968', '102');

-- ----------------------------
-- Table structure for t_sys_user
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_user`;
CREATE TABLE `t_sys_user`  (
  `id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '主键',
  `username` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名',
  `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '密码',
  `nick_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '昵称',
  `cell_phone` varchar(11) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '手机号',
  `mail` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '邮件',
  `birthday` datetime DEFAULT NULL COMMENT '生日',
  `status` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '状态(0-正常,1-删除,2-禁用)',
  `account_type` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '1系统账号 2客户账号',
  `invite_code` varchar(60) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '邀请码',
  `sex` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '性别:0男 1女',
  `up_num` int(11) DEFAULT NULL COMMENT '所有获赞总量',
  `read_num` int(11) DEFAULT NULL COMMENT '所有文章阅读总量',
  `address` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '地址',
  `create_user` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '创建人',
  `create_date` datetime DEFAULT NULL COMMENT '创建时间',
  `sign` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '用户签名',
  `picture_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '用户头像'
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-用户表' ROW_FORMAT = Compact;

-- ----------------------------
-- Records of t_sys_user
-- ----------------------------
INSERT INTO `t_sys_user` VALUES ('276866508766838784', 'liqingwei', 'E10ADC3949BA59ABBE56E057F20F883E', '李庆伟', '15801174628', 'liqingwei01@cnpc.cn', NULL, '0', '1', '3781941dd39446b89e98cb661766aade', NULL, 0, 0, NULL, NULL, '2021-08-26 15:59:31', NULL, NULL);
INSERT INTO `t_sys_user` VALUES ('277657251341139964', 'zhangsan', 'E10ADC3949BA59ABBE56E057F20F883E', '张三', '15801174626', 'zhangsan@qq.com', '2021-08-04 00:00:00', '0', '1', 'ea819ca462914e938943752d48ae8bcc', '0', 0, 0, '河南北京北', 'admin', '2021-08-28 20:21:38', '啥也不是。。。', '287348042074423296');

-- ----------------------------
-- Table structure for t_sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_user_role`;
CREATE TABLE `t_sys_user_role`  (
  `id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '主键',
  `user_id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户id',
  `role_id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色id',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-用户角色中间表' ROW_FORMAT = Compact;

-- ----------------------------
-- Records of t_sys_user_role
-- ----------------------------
INSERT INTO `t_sys_user_role` VALUES ('111', '276866508766838784', '277144675716956160');
INSERT INTO `t_sys_user_role` VALUES ('222', '277657251341139964', '277144172094291968');

SET FOREIGN_KEY_CHECKS = 1;

测试【把登录接口加到swagger中了】:

访问地址:http://localhost:8080/swagger-ui.html

总结

一点点。。。。。。。。。。。

  • 8
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
好的,下面是SpringBoot+Security+JWT的动态授权的实现步骤: 1. 首先,我们需要添加Spring SecurityJWT的依赖。在pom.xml文件中添加如下代码: ``` <!-- Spring Security --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- JWT --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> ``` 2. 添加JWT的配置类。创建一个JwtConfig类,用于生成JWT Token和解析JWT Token。代码如下: ``` @Configuration public class JwtConfig { private String secret = "jwt_secret_key"; private long expire = 604800000; @Bean public JwtAuthTokenGenerator jwtAuthTokenGenerator() { return new JwtAuthTokenGenerator(secret, expire); } @Bean public JwtAuthTokenVerifier jwtAuthTokenVerifier() { return new JwtAuthTokenVerifier(secret); } } ``` 3. 添加Spring Security的配置类。创建一个SecurityConfig类,配置Spring Security的一些基本设置。代码如下: ``` @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable().authorizeRequests() .antMatchers("/login").permitAll() .anyRequest().authenticated() .and() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); http.addFilterBefore(new JwtAuthenticationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(jwtAuthenticationProvider()); } @Bean public JwtAuthenticationProvider jwtAuthenticationProvider() { return new JwtAuthenticationProvider(jwtAuthTokenVerifier()); } } ``` 4. 添加JwtAuthenticationFilter类。创建一个JwtAuthenticationFilter类,用于在每个请求中验证JWT Token。代码如下: ``` public class JwtAuthenticationFilter extends OncePerRequestFilter { private AuthenticationManager authenticationManager; public JwtAuthenticationFilter(AuthenticationManager authenticationManager) { this.authenticationManager = authenticationManager; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String token = getToken(request); if (token != null) { JwtAuthToken authToken = new JwtAuthToken(token); Authentication authentication = authenticationManager.authenticate(authToken); SecurityContextHolder.getContext().setAuthentication(authentication); } filterChain.doFilter(request, response); } private String getToken(HttpServletRequest request) { String header = request.getHeader("Authorization"); if (header != null && header.startsWith("Bearer ")) { return header.substring(7); } return null; } } ``` 5. 添加JwtAuthenticationProvider类。创建一个JwtAuthenticationProvider类,用于验证JWT Token是否有效。代码如下: ``` public class JwtAuthenticationProvider implements AuthenticationProvider { private JwtAuthTokenVerifier jwtAuthTokenVerifier; public JwtAuthenticationProvider(JwtAuthTokenVerifier jwtAuthTokenVerifier) { this.jwtAuthTokenVerifier = jwtAuthTokenVerifier; } @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { JwtAuthToken authToken = (JwtAuthToken)authentication; String token = authToken.getToken(); if (jwtAuthTokenVerifier.verify(token)) { return new JwtAuthenticatedUser(token); } throw new BadCredentialsException("Invalid JWT token"); } @Override public boolean supports(Class<?> authentication) { return JwtAuthToken.class.isAssignableFrom(authentication); } } ``` 6. 添加JwtAuthToken类。创建一个JwtAuthToken类,用于包装JWT Token。代码如下: ``` public class JwtAuthToken extends AbstractAuthenticationToken { private String token; public JwtAuthToken(String token) { super(null); this.token = token; } @Override public Object getCredentials() { return token; } @Override public Object getPrincipal() { return null; } } ``` 7. 添加JwtAuthenticatedUser类。创建一个JwtAuthenticatedUser类,用于标识已通过验证的用户。代码如下: ``` public class JwtAuthenticatedUser implements Authentication { private String token; public JwtAuthenticatedUser(String token) { this.token = token; } @Override public Collection<? extends GrantedAuthority> getAuthorities() { return Collections.emptyList(); } @Override public Object getCredentials() { return null; } @Override public Object getDetails() { return null; } @Override public Object getPrincipal() { return token; } @Override public boolean isAuthenticated() { return true; } @Override public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { throw new UnsupportedOperationException(); } @Override public String getName() { return null; } } ``` 8. 最后,添加一个LoginController类,用于登录并获取JWT Token。代码如下: ``` @RestController public class LoginController { @Autowired private JwtAuthTokenGenerator jwtAuthTokenGenerator; @PostMapping("/login") public ResponseEntity<String> login(@RequestBody User user) { if (user.getUsername().equals("admin") && user.getPassword().equals("admin")) { String token = jwtAuthTokenGenerator.generateToken(user.getUsername()); return ResponseEntity.ok(token); } else { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } } } ``` 这就是SpringBoot+Security+JWT的动态授权的实现步骤,希望对你有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值