Quellcode durchsuchen

项目初始化

zouguihou vor 2 Jahren
Commit
a585c26a80
37 geänderte Dateien mit 1467 neuen und 0 gelöschten Zeilen
  1. 146 0
      pom.xml
  2. 7 0
      src/main/java/com/welampiot/Main.java
  3. 13 0
      src/main/java/com/welampiot/ServerApplication.java
  4. 33 0
      src/main/java/com/welampiot/common/BaseResult.java
  5. 35 0
      src/main/java/com/welampiot/common/BusinessException.java
  6. 5 0
      src/main/java/com/welampiot/common/Constant.java
  7. 33 0
      src/main/java/com/welampiot/common/ResultEnum.java
  8. 168 0
      src/main/java/com/welampiot/configuration/DruidConfig.java
  9. 14 0
      src/main/java/com/welampiot/configuration/ServiceConfiguration.java
  10. 32 0
      src/main/java/com/welampiot/controller/UserController.java
  11. 15 0
      src/main/java/com/welampiot/dao/UserDao.java
  12. 18 0
      src/main/java/com/welampiot/dto/MenuDTO.java
  13. 51 0
      src/main/java/com/welampiot/dto/UserDTO.java
  14. 47 0
      src/main/java/com/welampiot/handle/GlobalExceptionHandler.java
  15. 53 0
      src/main/java/com/welampiot/security/CustomizeAbstractSecurityInterceptor.java
  16. 47 0
      src/main/java/com/welampiot/security/CustomizeAccessDecisionManager.java
  17. 25 0
      src/main/java/com/welampiot/security/CustomizeAccessDeniedHandler.java
  18. 27 0
      src/main/java/com/welampiot/security/CustomizeAuthenticationEntryPoint.java
  19. 52 0
      src/main/java/com/welampiot/security/CustomizeAuthenticationFailureHandler.java
  20. 54 0
      src/main/java/com/welampiot/security/CustomizeAuthenticationSuccessHandler.java
  21. 49 0
      src/main/java/com/welampiot/security/CustomizeFilterInvocationSecurityMetadataSource.java
  22. 21 0
      src/main/java/com/welampiot/security/CustomizeLogoutSuccessHandler.java
  23. 25 0
      src/main/java/com/welampiot/security/CustomizeSessionInformationExpiredStrategy.java
  24. 18 0
      src/main/java/com/welampiot/security/MD5PasswordEncoder.java
  25. 55 0
      src/main/java/com/welampiot/security/ServerConfiguration.java
  26. 119 0
      src/main/java/com/welampiot/security/WebSecurityConfig.java
  27. 14 0
      src/main/java/com/welampiot/service/UserService.java
  28. 44 0
      src/main/java/com/welampiot/service/impl/UserDetailsServiceImpl.java
  29. 42 0
      src/main/java/com/welampiot/service/impl/UserServiceImpl.java
  30. 15 0
      src/main/java/com/welampiot/utils/MD5Utils.java
  31. 28 0
      src/main/java/com/welampiot/utils/WebUtils.java
  32. 16 0
      src/main/java/com/welampiot/vo/LoginVO.java
  33. 13 0
      src/main/java/com/welampiot/vo/MenuVO.java
  34. 31 0
      src/main/resources/application.yml
  35. 52 0
      src/main/resources/logback.xml
  36. 21 0
      src/main/resources/mapper/UserMapper.xml
  37. 29 0
      src/test/java/com/welampiot/service/UserServiceTest.java

+ 146 - 0
pom.xml

@@ -0,0 +1,146 @@
+<?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>
+
+    <groupId>com.welampiot</groupId>
+    <artifactId>CIS</artifactId>
+    <version>1.0-SNAPSHOT</version>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+        <log4j2.version>2.13.3</log4j2.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <!--    导入springboot版本和框架依赖     -->
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.5.1</version>
+        <relativePath></relativePath>
+    </parent>
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.mybatis.spring.boot</groupId>
+            <artifactId>mybatis-spring-boot-starter</artifactId>
+            <version>2.2.2</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid</artifactId>
+            <version>1.2.3</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid-spring-boot-starter</artifactId>
+            <version>1.1.20</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.9</version>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.junit.vintage</groupId>
+                    <artifactId>junit-vintage-engine</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-security</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.security</groupId>
+            <artifactId>spring-security-config</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+            <version>1.14</version>
+        </dependency>
+        <dependency>
+            <groupId>be.c4j.ee.security.octopus</groupId>
+            <artifactId>authentication</artifactId>
+            <version>0.9.7.2</version>
+            <type>pom</type>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.33</version>
+        </dependency>
+    </dependencies>
+    <!--添加maven插件,项目的打包工具,打成jar包,否则在打包运行时报错   -->
+    <build>
+        <finalName>CIS</finalName>
+        <resources>
+            <resource>
+                <directory>src/main/java</directory>
+                <includes>
+                    <include>**/*.xml</include>
+                    <include>**/*.yml</include>
+                    <include>**/*.properties</include>
+                </includes>
+            </resource>
+            <resource>
+                <directory>src/main/resources</directory>
+                <includes>
+                    <include>**/*.xml</include>
+                    <include>**/*.yml</include>
+                    <include>**/*.properties</include>
+                </includes>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.2.2.RELEASE</version>
+                <configuration>
+                    <mainClass>com.welampiot.ServerApplication</mainClass>
+                    <layout>JAR</layout>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                        <configuration>
+                            <attach>false</attach>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 7 - 0
src/main/java/com/welampiot/Main.java

@@ -0,0 +1,7 @@
+package com.welampiot;
+
+public class Main {
+    public static void main(String[] args) {
+        System.out.println("Hello world!");
+    }
+}

+ 13 - 0
src/main/java/com/welampiot/ServerApplication.java

@@ -0,0 +1,13 @@
+package com.welampiot;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+@MapperScan("com.welampiot.dao")
+public class ServerApplication {
+    public static void main(String[] args) {
+        SpringApplication.run((ServerApplication.class));
+    }
+}

+ 33 - 0
src/main/java/com/welampiot/common/BaseResult.java

@@ -0,0 +1,33 @@
+package com.welampiot.common;
+
+import lombok.Data;
+
+@Data
+public class BaseResult<T> {
+    private String responseCode;
+    private String responseMsg;
+    private T data;
+
+    public BaseResult(String responseCode, String responseMsg, T data) {
+        this.responseCode = responseCode;
+        this.responseMsg = responseMsg;
+        this.data = data;
+    }
+
+    public static BaseResult success(){
+        BaseResult vo = new BaseResult(Constant.success,"",null);
+        return vo;
+    }
+    public static BaseResult success(Object obj){
+        BaseResult vo = new BaseResult(Constant.success,"",obj);
+        return vo;
+    }
+    public static BaseResult fail(String code, String msg, Object obj){
+        BaseResult vo = new BaseResult(code,msg,obj);
+        return vo;
+    }
+    public static BaseResult fail(ResultEnum e){
+        BaseResult vo = new BaseResult(e.getCode(),e.getMsg(),null);
+        return vo;
+    }
+}

+ 35 - 0
src/main/java/com/welampiot/common/BusinessException.java

@@ -0,0 +1,35 @@
+package com.welampiot.common;
+
+public class BusinessException extends RuntimeException{
+
+    private String messgae;
+    private String code;
+
+    public BusinessException() {
+        super();
+    }
+
+    public BusinessException(String code, String message) {
+        super(message);
+        this.code = code;
+        this.messgae = message;
+    }
+    public BusinessException(ResultEnum resultEnum) {
+        this.code = resultEnum.getCode();
+        this.messgae = resultEnum.getMsg();
+    }
+
+    public BusinessException(String message) {
+        super(message);
+        this.messgae = message;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getMessage() {
+        return messgae;
+    }
+
+}

+ 5 - 0
src/main/java/com/welampiot/common/Constant.java

@@ -0,0 +1,5 @@
+package com.welampiot.common;
+
+public class Constant {
+    public static String success="000000";
+}

+ 33 - 0
src/main/java/com/welampiot/common/ResultEnum.java

@@ -0,0 +1,33 @@
+package com.welampiot.common;
+
+public enum ResultEnum {
+    LOGIN_ERROR("90001","用户名或者密码不正确"),
+    LOGIN_FAIL("90003","用户名或者密码不正确,登录失败"),
+    SESSION_OUT("90004","登录已过期"),
+    NOT_AUTH("90005","无权限访问"),
+    USERNAME_ERROR("90007","用户名错误"),
+    USER_NOT_LOGIN("90002","用户未登录");
+    private String code;
+    private String msg;
+
+    ResultEnum(String code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+}

+ 168 - 0
src/main/java/com/welampiot/configuration/DruidConfig.java

@@ -0,0 +1,168 @@
+//package com.welampiot.configuration;
+//
+//import com.alibaba.druid.filter.Filter;
+//import com.alibaba.druid.pool.DruidDataSource;
+//import com.alibaba.druid.support.http.StatViewServlet;
+//import com.alibaba.druid.support.http.WebStatFilter;
+//import com.alibaba.druid.wall.WallConfig;
+//import com.alibaba.druid.wall.WallFilter;
+//import org.slf4j.Logger;
+//import org.slf4j.LoggerFactory;
+//import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+//import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+//import org.springframework.boot.context.properties.ConfigurationProperties;
+//import org.springframework.boot.web.servlet.FilterRegistrationBean;
+//import org.springframework.boot.web.servlet.ServletRegistrationBean;
+//import org.springframework.context.annotation.Bean;
+//import org.springframework.context.annotation.ComponentScan;
+//import org.springframework.context.annotation.Configuration;
+//
+//import javax.sql.DataSource;
+//import java.sql.SQLException;
+//import java.util.*;
+//
+//@ConditionalOnMissingBean(DataSource.class)
+//@ConditionalOnClass(DruidDataSource.class)
+//@Configuration
+//@ComponentScan
+//public class DruidConfig {
+//    private Logger logger = LoggerFactory.getLogger(DruidConfig.class);
+//
+//    @Bean
+//    @ConfigurationProperties(prefix = "spring.datasource")
+//    public DataSource druidDataSource() {
+//        DruidDataSource dataSource = new DruidDataSource();
+//        try {
+//            // 启动程序时,在连接池中初始化多少个连接(10-50已足够)
+//            dataSource.setInitialSize(5);
+//            // 回收空闲连接时,将保证至少有 minIdle 个连接(与 initialSize 相同)
+//            dataSource.setMinIdle(5);
+//            // 连接池中最多支持多少个活动会话
+//            dataSource.setMaxActive(100);
+//            // 程序向连接池中请求连接时,超过 maxWait 的值后,认为本次请求失败,即连接池,没有可用连接,单位毫秒,设置 -1 时表示无限等待(建议值为100)
+//            dataSource.setMaxWait(100);
+//            /*
+//                缓存通过以下两个方法发起的 SQL:
+//                public PreparedStatement prepareStatement(String sql)
+//                public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
+//                (建议值为 true)
+//             */
+//            dataSource.setPoolPreparedStatements(true);
+//            // 每个连接最多缓存多少个 SQL(建议值为 20)
+//            dataSource.setMaxPoolPreparedStatementPerConnectionSize(20);
+//            // 检查空闲连接的频率,单位毫秒,非正整数时表示不进行检查(建议值:2000)
+//            dataSource.setTimeBetweenEvictionRunsMillis(2000);
+//            // 连接池中某个连接的空闲时长达到 N 毫秒后, 连接池在下次检查空闲连接时,将回收该连接,要小于防火墙超时设置 net.netfilter.nf_conntrack_tcp_timeout_established 的设置
+//            dataSource.setMinEvictableIdleTimeMillis(600000);
+//            // 配置一个连接在池中最大生存的时间,单位是毫秒
+//            dataSource.setMaxEvictableIdleTimeMillis(900000);
+//            // 程序没有 close 连接且空闲时长超过 minEvictableIdleTimeMillis,则会执行 validationQuery 指定的 SQL,以保证该程序连接不会池 kill 掉,其范围不超过 minIdle 指定的连接个数(建议值为 true)
+//            dataSource.setKeepAlive(true);
+//            // 检查池中的连接是否仍可用的 SQL 语句,druid 会连接到数据库执行该 SQL,如果正常返回,则表示连接可用,否则表示连接不可用
+//            dataSource.setValidationQuery("SELECT 1");
+//            // 当程序请求连接,池在分配连接时,是否先检查该连接是否有效(高效,并且保证安全性;建议值为 true)
+//            dataSource.setTestWhileIdle(true);
+//            // 程序申请连接时,进行连接有效性检查(低效,影响性能;建议值为 false)
+//            dataSource.setTestOnBorrow(false);
+//            // 程序返还连接时,进行连接有效性检查(低效,影响性能;建议值为 false)
+//            dataSource.setTestOnReturn(false);
+//            // 物理连接初始化的时候执行的 sql
+//            Collection<String> connectionInitSqls = new ArrayList<>(10);
+//            connectionInitSqls.add("SELECT 1 FROM DUAL");
+//            dataSource.setConnectionInitSqls(connectionInitSqls);
+//            /*
+//                这里配置的是插件,常用的插件有:
+//                监控统计:stat
+//                日志监控:log4j2
+//                防御 SQL 注入:wall
+//             */
+//            dataSource.setFilters("stat,log4j2");
+//            // 是否合并多个 DruidDataSource 的监控数据
+//            dataSource.setUseGlobalDataSourceStat(true);
+//            // 监控统计
+//            // 是否启用慢 SQL 记录
+//            dataSource.addConnectionProperty("druid.stat.logSlowSql", "true");
+//            // 执行时间超过 slowSqlMillis 的就是慢,单位毫秒(建议值 500)
+//            dataSource.addConnectionProperty("druid.stat.slowSqlMillis", "500");
+//            // 要求程序从池中 get 到连接后,N 秒后必须 close,否则 druid 会强制回收该连接,不管该连接中是活动还是空闲,以防止进程不会进行 close 而霸占连接(建议值为 false,当发现程序有未正常 close 连接时设置为 true)
+////            dataSource.setRemoveAbandoned(false);
+//            // 设置 druid 强制回收连接的时限,当程序从池中 get 到连接开始算起,超过此值后,druid将强制回收该连接,单位秒(应大于业务运行最长时间)
+////            dataSource.setRemoveAbandonedTimeout();
+//            // 当 druid 强制回收连接后,是否将 stack trace 记录到日志中(建议值为 true)
+////            dataSource.setLogAbandoned(true);
+//            // 连接属性。比如设置一些连接池统计方面的配置 druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
+////            dataSource.setConnectProperties();
+//
+//            // 防御 SQL 注入
+//            WallFilter wallFilter = new WallFilter();
+//            WallConfig config = new WallConfig();
+//            // 是否允许执行 DELETE 语句(建议值为 false)
+//            config.setDeleteAllow(false);
+//            // 是否允许删除表(建议值为 false)
+//            config.setDropTableAllow(false);
+//            wallFilter.setConfig(config);
+//
+//            // 插件代理
+//            List<Filter> proxyFilters = new ArrayList<>(10);
+//            proxyFilters.add(wallFilter);
+//            dataSource.setProxyFilters(proxyFilters);
+//
+//        } catch (SQLException e) {
+//            logger.error(e.toString());
+//        }
+//        return dataSource;
+//    }
+//
+//    @Bean
+//    public ServletRegistrationBean<StatViewServlet> statViewServlet() {
+//        // 监控信息显示页面
+//        StatViewServlet statViewServlet = new StatViewServlet();
+//        // 访问监控信息显示页面的 url 路径(建议值为 /druid/* )
+//        String urlPattern = "/druid/*";
+//
+//        ServletRegistrationBean<StatViewServlet> bean =
+//                new ServletRegistrationBean<>(statViewServlet, urlPattern);
+//
+//        Map<String, String> initParams = new HashMap<>();
+//        // 是否允许清空统计数据
+//        initParams.put("resetEnable", "false");
+//        // 登录监控信息显示页面的用户名
+//        initParams.put("loginUsername", "admin");
+//        // 登录监控信息显示页面的密码
+//        initParams.put("loginPassword", "admin");
+//        // 允许访问控制(格式:ip地址、ip地址/子网掩码位数)逗号分隔多个地址
+//        initParams.put("allow", "127.0.0.1");
+//        // 拒绝访问控制(格式:ip地址、ip地址/子网掩码位数)逗号分隔多个地址
+////        initParams.put("deny", "");
+//
+//        bean.setInitParameters(initParams);
+//        return bean;
+//    }
+//
+//    @Bean
+//    public FilterRegistrationBean<WebStatFilter> webStatFilter() {
+//        FilterRegistrationBean<WebStatFilter> bean = new FilterRegistrationBean<>();
+//        // 网络监控过滤器(用于采集 web-jdbc 关联监控的数据)
+//        bean.setFilter(new WebStatFilter());
+//        // 过滤所有的 url 路径
+//        Collection<String> urlPatterns = new ArrayList<>();
+//        urlPatterns.add("/*");
+//        bean.setUrlPatterns(urlPatterns);
+//
+//        Map<String, String> initParams = new HashMap<>();
+//        // 排除不必要采集的 url 路径,以逗号“,”分割
+//        initParams.put("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,*.map,/druid/*");
+//        // 是否使用 session 监控功能
+//        initParams.put("sessionStatEnable", "true");
+//        // 是否使用 session 监控最大数量(默认是1000)
+//        initParams.put("sessionStatMaxCount", "1000");
+//        // 使得 druid 能够知道当前的 session 的用户是谁,根据需要,把改值修改为你 user 信息保存在 session 中的 sessionName
+//        initParams.put("principalSessionName", "session_user_key");
+//        // 如果你的 user 信息保存在 cookie 中,你可以配置 principalCookieName,使得 druid 知道当前的 user 是谁,根据需要,把该值修改为你 user 信息保存在 cookie 中的 cookieName
+//        initParams.put("principalCookieName", "cookie_user_key");
+//        // 是否监控单个 url 调用的 sql 列表
+//        initParams.put("profileEnable", "true");
+//        bean.setInitParameters(initParams);
+//        return bean;
+//    }
+//}

+ 14 - 0
src/main/java/com/welampiot/configuration/ServiceConfiguration.java

@@ -0,0 +1,14 @@
+//package com.welampiot.configuration;
+//
+//import org.springframework.context.annotation.Bean;
+//import org.springframework.context.annotation.Configuration;
+//
+//import java.sql.SQLException;
+//
+//@Configuration
+//public class ServiceConfiguration {
+//    @Bean
+//    public DefaultDataSourceBean datasource() throws SQLException{
+//
+//    }
+//}

+ 32 - 0
src/main/java/com/welampiot/controller/UserController.java

@@ -0,0 +1,32 @@
+package com.welampiot.controller;
+
+import com.welampiot.common.BaseResult;
+import com.welampiot.common.ResultEnum;
+import com.welampiot.dto.UserDTO;
+import com.welampiot.service.UserService;
+import com.welampiot.utils.MD5Utils;
+import com.welampiot.vo.LoginVO;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+
+@RestController
+@RequestMapping("/user")
+//@Slf4j
+public class UserController {
+    private final static Logger log = LoggerFactory.getLogger(UserController.class);
+
+    @Autowired
+    private UserService userService;
+
+    @RequestMapping(value = "/find",method = RequestMethod.POST)
+    @PreAuthorize(value = "isAuthenticated()")//需要登录才可以访问
+    public BaseResult<?> find(){
+        int num = userService.countUser();
+        return BaseResult.success(num);
+    }
+}

+ 15 - 0
src/main/java/com/welampiot/dao/UserDao.java

@@ -0,0 +1,15 @@
+package com.welampiot.dao;
+
+import com.welampiot.dto.MenuDTO;
+import com.welampiot.dto.UserDTO;
+import com.welampiot.vo.LoginVO;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface UserDao {
+    UserDTO getUserByUserName(LoginVO vo);
+    UserDTO findUserByUserName(@Param("username") String username);
+    UserDTO loadUserByUsername(@Param("username") String username);
+    List<MenuDTO> queryMenuList(List<String> idList);
+}

+ 18 - 0
src/main/java/com/welampiot/dto/MenuDTO.java

@@ -0,0 +1,18 @@
+package com.welampiot.dto;
+
+import lombok.Data;
+
+/**
+ * 菜单DTO
+ */
+@Data
+public class MenuDTO {
+    private int id;
+    private int parentId;//上级权限id
+    private String name;//权限名称
+    private String enName;//权限英文名称
+    private String ruName;//俄语名称
+    private int level;//权限等级
+    private int status;//权限状态(0 停用,1 启用)
+    private String action;
+}

+ 51 - 0
src/main/java/com/welampiot/dto/UserDTO.java

@@ -0,0 +1,51 @@
+package com.welampiot.dto;
+
+import lombok.Data;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+@Data
+public class UserDTO implements UserDetails{
+    private String username;
+    private String password;
+    private int status;
+    private String privilegeList;
+
+    @Override
+    public Collection<? extends GrantedAuthority> getAuthorities() {
+        List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
+        List<String> list = Arrays.asList(getPrivilegeList().split(","));
+        // 声明用户授权
+        list.forEach(sysPermission -> {
+            GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(sysPermission);
+            grantedAuthorities.add(grantedAuthority);
+        });
+        return grantedAuthorities;
+    }
+
+    @Override
+    public boolean isAccountNonExpired() {
+        return false;
+    }
+
+    @Override
+    public boolean isAccountNonLocked() {
+        return false;
+    }
+
+    @Override
+    public boolean isCredentialsNonExpired() {
+        return false;
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return true;
+    }
+}

+ 47 - 0
src/main/java/com/welampiot/handle/GlobalExceptionHandler.java

@@ -0,0 +1,47 @@
+package com.welampiot.handle;
+
+import com.welampiot.common.BaseResult;
+import com.welampiot.common.BusinessException;
+import com.welampiot.common.ResultEnum;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.validation.BindException;
+import org.springframework.validation.BindingResult;
+import org.springframework.validation.FieldError;
+import org.springframework.validation.ObjectError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.ServletRequestBindingException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import javax.validation.ConstraintViolationException;
+import java.util.List;
+
+/**
+ * 全局异常处理器
+ */
+@RestControllerAdvice
+@Slf4j
+public class GlobalExceptionHandler {
+
+    /**
+     * 对异常做处理
+     * @param e
+     * @return
+     */
+    @ExceptionHandler(Exception.class)
+    public BaseResult<?> exceptionHandle(Exception e){
+        // 后续可考虑增加业务异常
+
+        //入参校验异常
+        if(e instanceof ServletRequestBindingException || e instanceof BindException){
+            return BaseResult.fail("400401",e.getMessage(),null);
+        }else if(e instanceof BusinessException){
+            return BaseResult.fail(((BusinessException) e).getCode(),e.getMessage(),null);
+        }else if(e instanceof AccessDeniedException){
+            return BaseResult.fail(ResultEnum.NOT_AUTH);
+        }
+        log.error("系统异常",e);
+        return BaseResult.fail("999","系统繁忙,请稍后再试",null);
+    }
+}

+ 53 - 0
src/main/java/com/welampiot/security/CustomizeAbstractSecurityInterceptor.java

@@ -0,0 +1,53 @@
+package com.welampiot.security;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.SecurityMetadataSource;
+import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
+import org.springframework.security.access.intercept.InterceptorStatusToken;
+import org.springframework.security.web.FilterInvocation;
+import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.*;
+import java.io.IOException;
+
+@Component
+public class CustomizeAbstractSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
+    @Autowired
+    private FilterInvocationSecurityMetadataSource securityMetadataSource;
+
+    @Autowired
+    public void setMyAccessDecisionManager(CustomizeAccessDecisionManager accessDecisionManager) {
+        super.setAccessDecisionManager(accessDecisionManager);
+    }
+
+    @Override
+    public Class<?> getSecureObjectClass() {
+        return FilterInvocation.class;
+    }
+
+    @Override
+    public SecurityMetadataSource obtainSecurityMetadataSource() {
+        return this.securityMetadataSource;
+    }
+
+    @Override
+    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
+            throws IOException, ServletException {
+        FilterInvocation fi = new FilterInvocation(servletRequest, servletResponse, filterChain);
+        invoke(fi);
+    }
+
+    public void invoke(FilterInvocation fi) throws IOException, ServletException {
+        //fi里面有一个被拦截的url
+        //里面调用MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限
+        //再调用MyAccessDecisionManager的decide方法来校验用户的权限是否足够
+        InterceptorStatusToken token = super.beforeInvocation(fi);
+        try {
+            //执行下一个拦截器
+            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
+        } finally {
+            super.afterInvocation(token, null);
+        }
+    }
+}

+ 47 - 0
src/main/java/com/welampiot/security/CustomizeAccessDecisionManager.java

@@ -0,0 +1,47 @@
+package com.welampiot.security;
+
+import org.springframework.security.access.AccessDecisionManager;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.access.ConfigAttribute;
+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;
+import java.util.Iterator;
+
+/**
+ * 访问决策管理器
+ */
+@Component
+public class CustomizeAccessDecisionManager implements AccessDecisionManager {
+    @Override
+    public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> collection)
+            throws AccessDeniedException, InsufficientAuthenticationException {
+//        Iterator<ConfigAttribute> iterator = collection.iterator();
+//        while (iterator.hasNext()) {
+//            ConfigAttribute ca = iterator.next();
+//            //当前请求需要的权限
+//            String needRole = ca.getAttribute();
+//            //当前用户所具有的权限
+//            Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
+//            for (GrantedAuthority authority : authorities) {
+//                if (authority.getAuthority().equals(needRole)) {
+//                    return;
+//                }
+//            }
+//        }
+//        throw new AccessDeniedException("权限不足!");
+    }
+
+    @Override
+    public boolean supports(ConfigAttribute configAttribute) {
+        return true;
+    }
+
+    @Override
+    public boolean supports(Class<?> aClass) {
+        return true;
+    }
+}

+ 25 - 0
src/main/java/com/welampiot/security/CustomizeAccessDeniedHandler.java

@@ -0,0 +1,25 @@
+package com.welampiot.security;
+
+import com.alibaba.fastjson.JSON;
+import com.welampiot.common.BaseResult;
+import com.welampiot.common.ResultEnum;
+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;
+@Component
+public class CustomizeAccessDeniedHandler implements AccessDeniedHandler {
+    @Override
+    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e)
+            throws IOException, ServletException {
+
+        //处理编码方式,防止中文乱码的情况
+        httpServletResponse.setContentType("text/json;charset=utf-8");
+        //塞到HttpServletResponse中返回给前台
+        httpServletResponse.getWriter().write(JSON.toJSONString(BaseResult.fail(ResultEnum.NOT_AUTH)));
+    }
+}

+ 27 - 0
src/main/java/com/welampiot/security/CustomizeAuthenticationEntryPoint.java

@@ -0,0 +1,27 @@
+package com.welampiot.security;
+
+import com.alibaba.fastjson.JSON;
+import com.welampiot.common.BaseResult;
+import com.welampiot.common.ResultEnum;
+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;
+
+/**
+ * @Description: 匿名用户访问无权限资源时的异常
+ */
+@Component
+public class CustomizeAuthenticationEntryPoint implements AuthenticationEntryPoint {
+    @Override
+    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e)
+            throws IOException, ServletException {
+        BaseResult result = BaseResult.fail(ResultEnum.USER_NOT_LOGIN);
+        httpServletResponse.setContentType("text/json;charset=utf-8");
+        httpServletResponse.getWriter().write(JSON.toJSONString(result));
+    }
+}

+ 52 - 0
src/main/java/com/welampiot/security/CustomizeAuthenticationFailureHandler.java

@@ -0,0 +1,52 @@
+package com.welampiot.security;
+
+import com.alibaba.fastjson.JSON;
+import com.welampiot.common.BaseResult;
+import com.welampiot.common.ResultEnum;
+import com.welampiot.utils.WebUtils;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.authentication.AuthenticationFailureHandler;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * 登录失败处理逻辑
+ */
+@Component
+public class CustomizeAuthenticationFailureHandler implements AuthenticationFailureHandler {
+    @Override
+    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
+        //返回json数据失败信息
+//        if (e instanceof AccountExpiredException) {
+//            //账号过期
+//            result = ResultTool.fail(ResultCode.USER_ACCOUNT_EXPIRED);
+//        } else if (e instanceof BadCredentialsException) {
+//            //密码错误
+//            result = ResultTool.fail(ResultCode.USER_CREDENTIALS_ERROR);
+//        } else if (e instanceof CredentialsExpiredException) {
+//            //密码过期
+//            result = ResultTool.fail(ResultCode.USER_CREDENTIALS_EXPIRED);
+//        } else if (e instanceof DisabledException) {
+//            //账号不可用
+//            result = ResultTool.fail(ResultCode.USER_ACCOUNT_DISABLE);
+//        } else if (e instanceof LockedException) {
+//            //账号锁定
+//            result = ResultTool.fail(ResultCode.USER_ACCOUNT_LOCKED);
+//        } else if (e instanceof InternalAuthenticationServiceException) {
+//            //用户不存在
+//            result = ResultTool.fail(ResultCode.USER_ACCOUNT_NOT_EXIST);
+//        }else{
+//            //其他错误
+//            result = ResultTool.fail(ResultCode.COMMON_FAIL);
+//        }
+        //处理编码方式,防止中文乱码的情况
+//        httpServletResponse.setContentType("text/json;charset=utf-8");
+        //塞到HttpServletResponse中返回给前台
+//        httpServletResponse.getWriter().write(JSON.toJSONString(BaseResult.fail(ResultEnum.LOGIN_FAIL)));
+        WebUtils.renderString(httpServletResponse,BaseResult.fail(ResultEnum.LOGIN_FAIL));
+    }
+}

+ 54 - 0
src/main/java/com/welampiot/security/CustomizeAuthenticationSuccessHandler.java

@@ -0,0 +1,54 @@
+package com.welampiot.security;
+
+import com.alibaba.fastjson.JSON;
+import com.welampiot.common.BaseResult;
+import com.welampiot.dto.MenuDTO;
+import com.welampiot.dto.UserDTO;
+import com.welampiot.service.UserService;
+import com.welampiot.vo.MenuVO;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@Component
+public class CustomizeAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
+
+    @Autowired
+    private UserService userService;
+
+    @Override
+    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication)
+            throws IOException, ServletException {
+        User userDetails = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
+        UserDTO userDTO = userService.getUserByUserName(userDetails.getUsername());
+        List<String> idList = Arrays.asList(userDTO.getPrivilegeList().split(","));
+        List<MenuDTO> menuDTOList = userService.queryMenuList(idList);
+        List<MenuVO> voList = new ArrayList<>();
+        for(MenuDTO dto:menuDTOList){
+            MenuVO vo = new MenuVO();
+            BeanUtils.copyProperties(dto,vo);
+            voList.add(vo);
+        }
+        //此处还可以进行一些处理,比如登录成功之后可能需要返回给前台当前用户有哪些菜单权限,
+        //进而前台动态的控制菜单的显示等,具体根据自己的业务需求进行扩展
+
+        //返回json数据
+        BaseResult result = BaseResult.success(voList);
+        //处理编码方式,防止中文乱码的情况
+        httpServletResponse.setContentType("text/json;charset=utf-8");
+        //塞到HttpServletResponse中返回给前台
+        httpServletResponse.getWriter().write(JSON.toJSONString(result));
+    }
+}

+ 49 - 0
src/main/java/com/welampiot/security/CustomizeFilterInvocationSecurityMetadataSource.java

@@ -0,0 +1,49 @@
+package com.welampiot.security;
+
+import com.welampiot.service.UserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.ConfigAttribute;
+import org.springframework.security.web.FilterInvocation;
+import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
+import org.springframework.stereotype.Component;
+import org.springframework.util.AntPathMatcher;
+
+import java.util.Collection;
+
+/**
+ * 安全元数据源
+ */
+@Component
+public class CustomizeFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
+
+    private AntPathMatcher antPathMatcher = new AntPathMatcher();
+    @Autowired
+    private UserService userService;
+    @Override
+    public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {
+        //获取请求地址
+        String requestUrl = ((FilterInvocation) o).getRequestUrl();
+        //查询具体某个接口的权限
+//        List<SysPermission> permissionList =  sysPermissionService.selectListByPath(requestUrl);
+//        if(permissionList == null || permissionList.size() == 0){
+            //请求路径没有配置权限,表明该请求接口可以任意访问
+            return null;
+//        }
+//        String[] attributes = new String[permissionList.size()];
+//        for(int i = 0;i<permissionList.size();i++){
+//            attributes[i] = permissionList.get(i).getPermissionCode();
+//        }
+//        return SecurityConfig.createList(attributes);
+    }
+
+    @Override
+    public Collection<ConfigAttribute> getAllConfigAttributes() {
+        return null;
+    }
+
+    @Override
+    public boolean supports(Class<?> aClass) {
+        return true;
+    }
+
+}

+ 21 - 0
src/main/java/com/welampiot/security/CustomizeLogoutSuccessHandler.java

@@ -0,0 +1,21 @@
+package com.welampiot.security;
+
+import com.alibaba.fastjson.JSON;
+import com.welampiot.common.BaseResult;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+@Component
+public class CustomizeLogoutSuccessHandler implements LogoutSuccessHandler {
+    @Override
+    public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication)
+            throws IOException, ServletException {
+        httpServletResponse.setContentType("text/json;charset=utf-8");
+        httpServletResponse.getWriter().write(JSON.toJSONString(BaseResult.success()));
+    }
+}

+ 25 - 0
src/main/java/com/welampiot/security/CustomizeSessionInformationExpiredStrategy.java

@@ -0,0 +1,25 @@
+package com.welampiot.security;
+
+import com.alibaba.fastjson.JSON;
+import com.welampiot.common.BaseResult;
+import com.welampiot.common.ResultEnum;
+import org.springframework.security.web.session.SessionInformationExpiredEvent;
+import org.springframework.security.web.session.SessionInformationExpiredStrategy;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * 会话信息过期策略
+ */
+@Component
+public class CustomizeSessionInformationExpiredStrategy implements SessionInformationExpiredStrategy {
+    @Override
+    public void onExpiredSessionDetected(SessionInformationExpiredEvent sessionInformationExpiredEvent) throws IOException, ServletException {
+        HttpServletResponse httpServletResponse = sessionInformationExpiredEvent.getResponse();
+        httpServletResponse.setContentType("text/json;charset=utf-8");
+        httpServletResponse.getWriter().write(JSON.toJSONString(BaseResult.success(ResultEnum.USER_NOT_LOGIN)));
+    }
+}

+ 18 - 0
src/main/java/com/welampiot/security/MD5PasswordEncoder.java

@@ -0,0 +1,18 @@
+package com.welampiot.security;
+
+import com.welampiot.utils.MD5Utils;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Component;
+
+@Component
+public class MD5PasswordEncoder implements PasswordEncoder {
+    @Override
+    public String encode(CharSequence charSequence) {
+        return MD5Utils.encoderMD5(charSequence.toString());
+    }
+
+    @Override
+    public boolean matches(CharSequence charSequence, String encoderPasseord) {
+        return MD5Utils.encoderMD5(charSequence.toString()).equals(encoderPasseord);
+    }
+}

+ 55 - 0
src/main/java/com/welampiot/security/ServerConfiguration.java

@@ -0,0 +1,55 @@
+package com.welampiot.security;
+
+import com.alibaba.fastjson.serializer.SerializeConfig;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.alibaba.fastjson.serializer.ToStringSerializer;
+import com.alibaba.fastjson.support.config.FastJsonConfig;
+import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class ServerConfiguration {
+
+    /**
+     * 跨域设置
+     * @return
+     */
+    @Bean
+    public WebMvcConfigurer corsConfigurate(){
+        return new WebMvcConfigurer() {
+            @Override
+            public void addCorsMappings(CorsRegistry registry) {
+                registry.addMapping("/*")
+                        .allowedOrigins("*")
+                        .allowedMethods("*")
+                        .allowedHeaders("*")
+                        .allowCredentials(true)
+                        .exposedHeaders(HttpHeaders.SET_COOKIE)
+                        .maxAge(3600);
+            }
+        };
+    }
+
+    /**
+     * 使用@Bean注入fastJsonHttpMessageConvert
+     */
+    @Bean
+    public HttpMessageConverter fastJsonHttpMessageConverters() {
+        //1.需要定义一个Convert转换消息的对象
+        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
+        FastJsonConfig fastJsonConfig = new FastJsonConfig();
+        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
+        //设置fastjson日期转换格式yyyy-mm-dd HH:mm:ss
+        fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
+        SerializeConfig.globalInstance.put(Long.class, ToStringSerializer.instance);
+        fastJsonConfig.setSerializeConfig(SerializeConfig.globalInstance);
+        fastConverter.setFastJsonConfig(fastJsonConfig);
+        HttpMessageConverter<?> converter = fastConverter;
+        return converter;
+    }
+}

+ 119 - 0
src/main/java/com/welampiot/security/WebSecurityConfig.java

@@ -0,0 +1,119 @@
+package com.welampiot.security;
+
+import com.welampiot.service.impl.UserDetailsServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.ObjectPostProcessor;
+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.core.userdetails.UserDetailsService;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
+import org.springframework.security.web.authentication.AuthenticationFailureHandler;
+import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
+
+import javax.annotation.Resource;
+
+@Configuration
+@EnableWebSecurity//开启Spring Security的功能
+//prePostEnabled属性决定Spring Security在接口前注解是否可用@PreAuthorize,@PostAuthorize等注解,设置为true,会拦截加了这些注解的接口
+@EnableGlobalMethodSecurity(prePostEnabled=true)
+public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
+    @Autowired
+    private UserDetailsService userDetailsService;
+    @Resource
+    private MD5PasswordEncoder md5PasswordEncoder;
+    //登录成功处理逻辑
+    @Autowired
+    CustomizeAuthenticationSuccessHandler authenticationSuccessHandler;
+
+    //登录失败处理逻辑
+    @Autowired
+    CustomizeAuthenticationFailureHandler authenticationFailureHandler;
+
+    //权限拒绝处理逻辑
+    @Autowired
+    CustomizeAccessDeniedHandler accessDeniedHandler;
+
+    //匿名用户访问无权限资源时的异常
+    @Autowired
+    CustomizeAuthenticationEntryPoint authenticationEntryPoint;
+
+    //会话失效(账号被挤下线)处理逻辑
+    @Autowired
+    CustomizeSessionInformationExpiredStrategy sessionInformationExpiredStrategy;
+
+    //登出成功处理逻辑
+    @Autowired
+    CustomizeLogoutSuccessHandler logoutSuccessHandler;
+
+    //访问决策管理器
+    @Autowired
+    CustomizeAccessDecisionManager accessDecisionManager;
+
+    //实现权限拦截
+    @Autowired
+    CustomizeFilterInvocationSecurityMetadataSource securityMetadataSource;
+
+    @Autowired
+    private CustomizeAbstractSecurityInterceptor securityInterceptor;
+
+    @Bean
+    public UserDetailsService userDetailsService() {
+        //获取用户账号密码及权限信息
+        return new UserDetailsServiceImpl();
+    }
+
+    @Override
+    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+        auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
+    }
+
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http.cors().and().csrf().disable();
+        http.authorizeRequests().antMatchers("/login").anonymous().anyRequest().authenticated().
+//                antMatchers("/login").anonymous().
+//                antMatchers("/**").fullyAuthenticated().
+                        withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
+                    @Override
+                    public <O extends FilterSecurityInterceptor> O postProcess(O o) {
+                        o.setAccessDecisionManager(accessDecisionManager);//决策管理器
+                        o.setSecurityMetadataSource(securityMetadataSource);//安全元数据源
+                        return o;
+                    }
+                }).
+                //登出
+                and().logout().logoutSuccessUrl("/logout").
+//                permitAll().//允许所有用户
+                logoutSuccessHandler(logoutSuccessHandler).//登出成功处理逻辑
+                deleteCookies("JSESSIONID").//登出之后删除cookie
+                //登入
+                and().formLogin().loginProcessingUrl("/login").
+//                permitAll().//允许所有用户
+                successHandler(authenticationSuccessHandler).//登录成功处理逻辑
+                failureHandler(authenticationFailureHandler).//登录失败处理逻辑
+                //异常处理(权限拒绝、登录失效等)
+                and().exceptionHandling().accessDeniedHandler(accessDeniedHandler).//权限拒绝处理逻辑
+                authenticationEntryPoint(authenticationEntryPoint).//匿名用户访问无权限资源时的异常处理
+                //会话管理
+                and().sessionManagement().
+                maximumSessions(1).//同一账号同时登录最大用户数
+                expiredSessionStrategy(sessionInformationExpiredStrategy);//会话失效(账号被挤下线)处理逻辑
+        http.addFilterBefore(securityInterceptor, FilterSecurityInterceptor.class);
+    }
+
+    /**
+     * 指定加密方式
+     */
+    @Bean
+    public PasswordEncoder passwordEncoder(){
+        // 使用MD5加密密码
+        return new MD5PasswordEncoder();
+    }
+
+}

+ 14 - 0
src/main/java/com/welampiot/service/UserService.java

@@ -0,0 +1,14 @@
+package com.welampiot.service;
+
+import com.welampiot.dto.MenuDTO;
+import com.welampiot.dto.UserDTO;
+import com.welampiot.vo.LoginVO;
+
+import java.util.List;
+
+public interface UserService {
+    UserDTO getUserByUserName(LoginVO vo);
+    UserDTO getUserByUserName(String username);
+    List<MenuDTO> queryMenuList(List<String> list);
+    int countUser();
+}

+ 44 - 0
src/main/java/com/welampiot/service/impl/UserDetailsServiceImpl.java

@@ -0,0 +1,44 @@
+package com.welampiot.service.impl;
+
+import com.welampiot.common.BusinessException;
+import com.welampiot.common.ResultEnum;
+import com.welampiot.dao.UserDao;
+import com.welampiot.dto.UserDTO;
+import org.apache.commons.lang3.StringUtils;
+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.User;
+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 java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@Service
+public class UserDetailsServiceImpl implements UserDetailsService {
+    @Autowired
+    private UserDao userDao;
+    @Override
+    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+        if (StringUtils.isEmpty(username)) {
+            throw new BusinessException(ResultEnum.USERNAME_ERROR);
+        }
+        UserDTO user = userDao.loadUserByUsername(username);
+        if (user == null) {
+            throw new BusinessException(ResultEnum.USERNAME_ERROR);
+        }
+        List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
+        //获取该用户所拥有的权限
+        List<String> list = Arrays.asList(user.getPrivilegeList().split(","));
+        // 声明用户授权
+        list.forEach(sysPermission -> {
+            GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(sysPermission);
+            grantedAuthorities.add(grantedAuthority);
+        });
+        return new User(username,user.getPassword(),true,true,true,true,grantedAuthorities);
+    }
+}

+ 42 - 0
src/main/java/com/welampiot/service/impl/UserServiceImpl.java

@@ -0,0 +1,42 @@
+package com.welampiot.service.impl;
+
+import com.welampiot.dao.UserDao;
+import com.welampiot.dto.MenuDTO;
+import com.welampiot.dto.UserDTO;
+import com.welampiot.service.UserService;
+import com.welampiot.vo.LoginVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class UserServiceImpl implements UserService {
+
+    @Autowired
+    private UserDao userDao;
+    @Override
+    public UserDTO getUserByUserName(LoginVO vo) {
+        return userDao.getUserByUserName(vo);
+    }
+
+    @Override
+    public UserDTO getUserByUserName(String username) {
+        return userDao.findUserByUserName(username);
+    }
+
+    /**
+     * 查询菜单
+     * @param list
+     * @return
+     */
+    @Override
+    public List<MenuDTO> queryMenuList(List<String> list) {
+        return userDao.queryMenuList(list);
+    }
+
+    @Override
+    public int countUser() {
+        return 0;
+    }
+}

+ 15 - 0
src/main/java/com/welampiot/utils/MD5Utils.java

@@ -0,0 +1,15 @@
+package com.welampiot.utils;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.digest.DigestUtils;
+@Slf4j
+public class MD5Utils {
+    public static String encoderMD5(String inStr) {
+        return DigestUtils.md5Hex(inStr);
+    }
+
+    public static void main(String[] args) {
+        System.out.println(encoderMD5("123456"));
+    }
+}
+

+ 28 - 0
src/main/java/com/welampiot/utils/WebUtils.java

@@ -0,0 +1,28 @@
+package com.welampiot.utils;
+
+import com.alibaba.fastjson.JSON;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@Slf4j
+public class WebUtils
+{
+    /**
+     * 将字符串渲染到客户端
+     *
+     * @param response 渲染对象
+     */
+    public static void  renderString(HttpServletResponse response, Object o) {
+        try
+        {
+            response.setStatus(200);
+            response.setContentType("application/json");
+            response.setCharacterEncoding("utf-8");
+            response.getWriter().print(JSON.toJSONString(o));
+        }catch (IOException e){
+            log.error("renderString error",e);
+        }
+    }
+}

+ 16 - 0
src/main/java/com/welampiot/vo/LoginVO.java

@@ -0,0 +1,16 @@
+package com.welampiot.vo;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import java.io.Serializable;
+
+
+@Data
+public class LoginVO implements Serializable {
+    @NotEmpty(message = "username不允许为空")
+    private String username;
+    @NotEmpty(message = "password不允许为空")
+    private String password;
+    private String token;
+}

+ 13 - 0
src/main/java/com/welampiot/vo/MenuVO.java

@@ -0,0 +1,13 @@
+package com.welampiot.vo;
+
+import lombok.Data;
+
+@Data
+public class MenuVO {
+    private int id;
+    private int parentId;
+    private String name;//权限名称
+    private String enName;//权限英文名称
+    private String ruName;//俄语名称
+    private String action;
+}

+ 31 - 0
src/main/resources/application.yml

@@ -0,0 +1,31 @@
+server:
+  port: 8088
+  servlet:
+    context-path: /welampiot
+
+spring:
+  application:
+    name: welampiot
+  datasource:
+    driver-class-name: com.mysql.jdbc.Driver
+    url: jdbc:mysql://139.196.213.241:3306/welampiot?characterEncoding=utf-8&useSSL=false
+    username: welampiot
+    password: welampiot@2023
+    initialSize: 5
+    minIdle: 5
+    maxActive: 100
+    maxWait: 60000
+    #数据库连接中数据源类型
+    type: com.alibaba.druid.pool.DruidDataSource
+mybatis:
+  mapper-locations: classpath:/mapper/*.xml
+  check-config-location: true
+  type-aliases-package: com.welampiot
+debug: true
+
+logging:
+  file:
+    path: /logs/cis
+  level:
+      root: info
+  config: classpath:logback.xml

+ 52 - 0
src/main/resources/logback.xml

@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <!-- appender是configuration的子节点,是负责写日志的组件。 -->
+    <!-- ConsoleAppender:把日志输出到控制台 -->
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <!-- 默认情况下,每个日志事件都会立即刷新到基础输出流。 这种默认方法更安全,因为如果应用程序在没有正确关闭appender的情况下退出,则日志事件不会丢失。
+         但是,为了显着增加日志记录吞吐量,您可能希望将immediateFlush属性设置为false -->
+        <!--<immediateFlush>true</immediateFlush>-->
+        <encoder>
+            <!-- %37():如果字符没有37个字符长度,则左侧用空格补齐 -->
+            <!-- %-37():如果字符没有37个字符长度,则右侧用空格补齐 -->
+            <!-- %15.15():如果记录的线程字符长度小于15(第一个)则用空格在左侧补齐,如果字符长度大于15(第二个),则从开头开始截断多余的字符 -->
+            <!-- %-40.40():如果记录的logger字符长度小于40(第一个)则用空格在右侧补齐,如果字符长度大于40(第二个),则从开头开始截断多余的字符 -->
+            <!-- %msg:日志打印详情 -->
+            <!-- %n:换行符 -->
+            <!-- %highlight():转换说明符以粗体红色显示其级别为ERROR的事件,红色为WARN,BLUE为INFO,以及其他级别的默认颜色。 -->
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) --- [%15.15(%thread)] %cyan(%-40.40(%logger{40})) : %msg%n</pattern>
+            <!-- 控制台也要使用UTF-8,不要使用GBK,否则会中文乱码 -->
+            <charset>UTF-8</charset>
+        </encoder>
+    </appender>
+
+    <appender name="LOG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <encoder>
+            <pattern><![CDATA[%n[%d{yyyy-MM-dd HH:mm:ss.SSS}] [level: %p] [Thread: %t] [ Class:%c >> Method: %M:%L ]%n%p:%m%n]]></pattern>
+            <!-- 记录日志的编码:此处设置字符集 - -->
+            <charset>UTF-8</charset>
+        </encoder>
+        <file>logs/cis.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <!-- 日志文件的名字会根据fileNamePattern的值,每隔一段时间改变一次 -->
+            <fileNamePattern>logs/his/%d{yyyyMM}/cis.-%d{yyyyMMdd}.%i.log.gz</fileNamePattern>
+            <!-- 每产生一个日志文件,该日志文件的保存期限为30天, ps:maxHistory的单位是根据fileNamePattern中的翻转策略自动推算出来的,例如上面选用了yyyy-MM-dd,则单位为天
+            如果上面选用了yyyy-MM,则单位为月,另外上面的单位默认为yyyy-MM-dd-->
+            <maxHistory>30</maxHistory>
+            <!-- 每个日志文件到1G的时候开始切分,最多保留30天,但最大到200GB,哪怕没到30天也要删除多余的日志 -->
+            <totalSizeCap>50GB</totalSizeCap>
+            <!-- maxFileSize:这是活动文件的大小 -->
+            <maxFileSize>500MB</maxFileSize>
+        </rollingPolicy>
+    </appender>
+    <logger name="record" level="DEBUG" additivity="false">
+        <appender-ref ref="STDOUT"/>
+        <appender-ref ref="LOG_FILE"/>
+        <!--<appender-ref ref="myAppender"/>-->
+    </logger>
+    <root level="DEBUG">
+        <appender-ref ref="STDOUT"/>
+        <appender-ref ref="LOG_FILE"/>
+        <!--<appender-ref ref="mqAppender"/>-->
+    </root>
+</configuration>

+ 21 - 0
src/main/resources/mapper/UserMapper.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.welampiot.dao.UserDao">
+    <select id="getUserByUserName" resultType="com.welampiot.dto.UserDTO" parameterType="com.welampiot.vo.LoginVO">
+        select username,privilege_list privilegeList from user where username=#{username,jdbcType=VARCHAR}
+        and password=#{password,jdbcType=VARCHAR} and status=1
+    </select>
+    <select id="loadUserByUsername" resultType="com.welampiot.dto.UserDTO">
+        select username,password,status,privilege_list privilegeList from user where username=#{username,jdbcType=VARCHAR}
+    </select>
+    <select id="findUserByUserName" resultType="com.welampiot.dto.UserDTO">
+        select username,role,status,privilege_list privilegeList from user where username=#{username,jdbcType=VARCHAR}
+    </select>
+    <select id="queryMenuList" parameterType="list" resultType="com.welampiot.dto.MenuDTO">
+        select id,parentid parentId,name,en_name enName,ru_name ruName,level,action from privilnode where status=1
+        and id in
+        <foreach collection="list" item="id" separator="," open="(" close=")">
+            id
+        </foreach>
+    </select>
+</mapper>

+ 29 - 0
src/test/java/com/welampiot/service/UserServiceTest.java

@@ -0,0 +1,29 @@
+package com.welampiot.service;
+
+import com.welampiot.service.UserService;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class UserServiceTest {
+    @Autowired
+    private DataSource dataSource;
+//    @Autowired
+//    private UserService userService;
+
+    @Test
+    public void testConnection() throws SQLException {
+        System.out.println(dataSource.getClass());
+        Connection connection = dataSource.getConnection();
+        System.out.println(connection);
+        connection.close();
+    }
+}