1、基础技术框架
技术名称 | 版本 |
SpringBoot | 2.1.0.RELEASE |
Mybatis-Plus | 3.4.1 |
Lombok | 1.18.2 |
MySQL8 | 8.0.13 |
Alibaba Druid | 1.1.10 |
Thymelaf | 3.0.11 |
Alibaba Fastjson | 1.2.4 |
Hutool | 5.5.2 |
SpringSecurity | 5.5.1 |
2、完整pom.xml
<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.zzg</groupId>
<artifactId>cas-thymeleaf</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<encoding>UTF-8</encoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!--集成spring-security 安全框架 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- MyBatis-Plus 拓展 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
<!--lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--mysql-connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- druid-spring-boot-starter -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!-- 集成thymelaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- commons-lang -->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<!-- apache common 模块 -->
<!--commons-lang3 工具包 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<!--commons-codec 加密工具包 -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
<!--commons-net 网络工具包 -->
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.6</version>
</dependency>
<!--common-io 工具包 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<!--common-collection 工具包 -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
<!-- 集成fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.4</version>
</dependency>
<!-- 集成hutool-all 工具包 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.5.2</version>
</dependency>
</dependencies>
</project>
3、初始化脚本
CREATE TABLE IF NOT EXISTS `employee` (
`id` int(32) NOT NULL AUTO_INCREMENT COMMENT '主键',
`code` varchar(32) NOT NULL COMMENT '员工编号',
`name` varchar(64) NOT NULL COMMENT '员工名称',
`sex` int(2) NOT NULL DEFAULT '1' COMMENT '性别:1:男(默认) 2:女',
`birthday` datetime NOT NULL COMMENT '出生日期',
`passwd` varchar(32) NOT NULL COMMENT '员工密码',
`telephone` varchar(32) NOT NULL COMMENT '电话',
`note` varchar(128) DEFAULT NULL COMMENT '备注',
`work_year` int(2) NOT NULL COMMENT '工作年限',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='员工表';
-- 正在导出表 hotel.employee 的数据:~18 rows (大约)
/*!40000 ALTER TABLE `employee` DISABLE KEYS */;
INSERT INTO `employee` (`id`, `code`, `name`, `sex`, `birthday`, `passwd`, `telephone`, `note`, `work_year`) VALUES
(2, '0002', 'zhoucx', 1, '2021-12-20 00:00:00', '123456', '13267485563', NULL, 2),
(3, '003', 'zhoucy', 1, '2021-12-20 00:00:00', '123456', '13267485563', NULL, 2),
(4, '0004', 'zhouwz', 1, '2019-05-30 00:00:00', '123456', '13267485563', NULL, 2),
(5, '0005', 'zhouces', 1, '2019-05-30 00:00:00', '123456', '13267485563', NULL, 2),
(6, '0006', 'zhoucc', 1, '2019-05-30 00:00:00', '123456', '13267485563', NULL, 2),
(7, '0008', 'zhouyq', 1, '2019-05-30 00:00:00', '123456', '13267485563', NULL, 2),
(8, '0007', 'zhouhm', 1, '2019-05-30 00:00:00', '123456', '13267485563', NULL, 2),
(9, '0009', 'zhoucc', 1, '2021-12-20 00:00:00', '123456', '13267485563', NULL, 2),
(10, '0010', 'zhoucx', 1, '2019-05-30 00:00:00', '123456', '18898760514', NULL, 2),
(11, '0011', 'zhoucx', 1, '2019-05-30 00:00:00', '123456', '18898760514', NULL, 2),
(12, '0012', 'zhoucx', 1, '2019-05-30 00:00:00', '123456', '13267485563', NULL, 2),
(13, '0013', 'zhoucx', 1, '2019-05-30 00:00:00', '123456', '13267485563', NULL, 5),
(14, '0014', 'zhoucx', 1, '2021-12-20 00:00:00', '123456', '13267485563', NULL, 2),
(15, '0014', 'zhoucx', 1, '2021-12-20 00:00:00', '123456', '13267485563', NULL, 2),
(16, '0015', 'zhoucx', 1, '2021-12-20 00:00:00', '123456', '13267485563', NULL, 2),
(17, '0016', 'zhoucx', 1, '2019-05-30 00:00:00', '123456', '18898760514', NULL, 2),
(20, '0016', 'zhoucx', 1, '2019-05-30 00:00:00', '123456', '18898760514', NULL, 2),
(22, '0017', 'zhoucx', 1, '2019-05-30 00:00:00', '123456', '18898760514', NULL, 2);
/*!40000 ALTER TABLE `employee` ENABLE KEYS */;
-- 导出 表 hotel.t_sys_auth 结构
CREATE TABLE IF NOT EXISTS `t_sys_auth` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`auth_name` varchar(50) NOT NULL COMMENT '权限名称',
`permission` varchar(200) DEFAULT NULL COMMENT '权限标识',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='系统权限';
-- 正在导出表 hotel.t_sys_auth 的数据:~7 rows (大约)
/*!40000 ALTER TABLE `t_sys_auth` DISABLE KEYS */;
INSERT INTO `t_sys_auth` (`id`, `auth_name`, `permission`) VALUES
(1, '系统用户编辑权限', 'sys:user:edit'),
(2, '系统用户查询权限', 'sys:user:view'),
(3, '系统角色编辑权限', 'sys:role:edit'),
(4, '系统角色查询权限', 'sys:role:view'),
(5, '系统权限编辑权限', 'sys:auth:edit'),
(6, '系统权限查询权限', 'sys:auth:view'),
(7, '系统任务调度权限', 'sys:job');
/*!40000 ALTER TABLE `t_sys_auth` ENABLE KEYS */;
-- 导出 表 hotel.t_sys_role 结构
CREATE TABLE IF NOT EXISTS `t_sys_role` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`role_name` varchar(50) DEFAULT NULL COMMENT '角色名称',
`role_code` varchar(50) NOT NULL COMMENT '角色编码',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='系统角色';
-- 正在导出表 hotel.t_sys_role 的数据:~2 rows (大约)
/*!40000 ALTER TABLE `t_sys_role` DISABLE KEYS */;
INSERT INTO `t_sys_role` (`id`, `role_name`, `role_code`) VALUES
(1, '普通员工', 'USER'),
(2, '项目经理', 'PM');
/*!40000 ALTER TABLE `t_sys_role` ENABLE KEYS */;
-- 导出 表 hotel.t_sys_role_auth 结构
CREATE TABLE IF NOT EXISTS `t_sys_role_auth` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`role_id` bigint(20) DEFAULT NULL COMMENT '角色ID',
`auth_id` bigint(20) DEFAULT NULL COMMENT '权限ID',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='角色权限关系';
-- 正在导出表 hotel.t_sys_role_auth 的数据:~10 rows (大约)
/*!40000 ALTER TABLE `t_sys_role_auth` DISABLE KEYS */;
INSERT INTO `t_sys_role_auth` (`id`, `role_id`, `auth_id`) VALUES
(1, 2, 1),
(2, 1, 2),
(3, 2, 2),
(4, 2, 3),
(5, 1, 4),
(6, 2, 4),
(7, 2, 5),
(8, 1, 6),
(9, 2, 6),
(10, 2, 7);
/*!40000 ALTER TABLE `t_sys_role_auth` ENABLE KEYS */;
-- 导出 表 hotel.t_sys_user 结构
CREATE TABLE IF NOT EXISTS `t_sys_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`username` varchar(50) DEFAULT NULL COMMENT '用户名称',
`nickname` varchar(100) DEFAULT NULL COMMENT '用户昵称',
`password` varchar(255) DEFAULT NULL COMMENT '用户密码',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='系统用户';
-- 正在导出表 hotel.t_sys_user 的数据:~2 rows (大约)
/*!40000 ALTER TABLE `t_sys_user` DISABLE KEYS */;
INSERT INTO `t_sys_user` (`id`, `username`, `nickname`, `password`) VALUES
(1, 'user', 'C3Stones', '$2a$10$WXEPqxjMwY6d6A0hkeBtGu.acRRWUOJmX7oLUuYMHF1VWWUm4EqOC'),
(2, 'system', '管理员', '$2a$10$dmO7Uk9/lo1D5d1SvCGgWuB050a0E2uuBDNITEpWFiIfCg.3UbA8y');
/*!40000 ALTER TABLE `t_sys_user` ENABLE KEYS */;
-- 导出 表 hotel.t_sys_user_role 结构
CREATE TABLE IF NOT EXISTS `t_sys_user_role` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`user_id` bigint(20) DEFAULT NULL COMMENT '用户ID',
`role_id` bigint(20) DEFAULT NULL COMMENT '角色ID',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户角色关系';
-- 正在导出表 hotel.t_sys_user_role 的数据:~2 rows (大约)
/*!40000 ALTER TABLE `t_sys_user_role` DISABLE KEYS */;
INSERT INTO `t_sys_user_role` (`id`, `user_id`, `role_id`) VALUES
(1, 1, 1),
(2, 2, 2);
/*!40000 ALTER TABLE `t_sys_user_role`
4、功能效果截图
5、项目结构截图:
6、业务模块说明
com.zzg.entity = 实体对象定义
com.zzg.mapper= 接口映射
com.zzg.service= 服务定义
com.zzg.service.impl= 服务实列化
com.zzg.controller=业务控制层
com.zzg.common=通用功能封装
com.zzg.config=模块配置对象
com.zzg.security=安全模块对象
这里就不粘贴相关源码,直接查看源码提供下载地址。
7、通用模块说明
package com.zzg.common.converter;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
import org.springframework.util.NumberUtils;
public class ObjectToIntegerConverterFactory implements ConverterFactory<Integer, Integer> {
public <T extends Integer> Converter<Integer, T> getConverter(Class<T> targetType) {
// TODO Auto-generated method stub
return new ObjectToInteger(targetType);
}
// 私有内部类:实现Converter接口。用泛型边界约束一类类型
private static final class ObjectToInteger<T extends Integer> implements Converter<T, Integer> {
private final Class<T> targetType;
public ObjectToInteger(Class<T> targetType) {
this.targetType = targetType;
}
public Integer convert(T source) {
// TODO Auto-generated method stub
if(source == null) {
return 0;
}
return NumberUtils.parseNumber(String.valueOf(source), this.targetType);
}
}
}
package com.zzg.common;
import java.util.Map;
import org.springframework.core.convert.converter.ConverterFactory;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zzg.common.converter.ObjectToIntegerConverterFactory;
public abstract class AbstractCommonController<T> {
public static final String pageNo = "pageNo";
public static final String pageSize = "pageSize";
public Page<T> getPage(Map map){
ConverterFactory<Integer, Integer> converterFactory = new ObjectToIntegerConverterFactory();
Integer no = converterFactory.getConverter(Integer.class).convert(Integer.valueOf(String.valueOf(map.get(pageNo))));
Integer size = converterFactory.getConverter(Integer.class).convert(Integer.valueOf(String.valueOf(map.get(pageSize))));
return new Page<T>(no,size);
}
}
package com.zzg.common;
import java.io.PrintWriter;
import javax.servlet.ServletResponse;
import cn.hutool.json.JSONUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Response<T> {
/**
* 响应码
*/
private int code;
/**
* 响应消息体
*/
private String msg;
/**
* 响应数据
*/
private T data;
/**
* 失败响应
*
* @param code 响应码
* @param msg 响应消息体
* @param data 响应数据
* @return
*/
public static <T> Response<T> error(int code, String msg, T data) {
return new Response<T>(code, msg, data);
}
/**
* 失败响应
*
* @param msg 响应消息体
* @return
*/
public static <T> Response<T> error(String msg) {
return new Response<T>(500, msg, null);
}
/**
* 成功响应
*
* @param data 响应数据
* @return
*/
public static <T> Response<T> success(T data) {
return new Response<T>(200, null, data);
}
/**
* 成功响应
*
* @param msg 响应消息体
* @return
*/
public static <T> Response<T> success(String msg) {
return new Response<T>(200, msg, null);
}
/**
* 成功响应
*
* @param msg 响应消息体
* @param data 响应数据
* @return
*/
public static <T> Response<T> success(String msg, T data) {
return new Response<T>(200, msg, data);
}
/**
* Response输出Json格式
*
* @param response
* @param data 返回数据
*/
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(JSONUtil.toJsonStr(data));
out.flush();
} catch (Exception e) {
} finally {
if (out != null) {
out.close();
}
}
}
}
8、系统初始化配置和程序入口
package com.zzg.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
/**
* MyBatisPlus 配置类
* @author Administrator
*
*/
@Configuration
public class MyBatisPlusConfig {
/**
* 分页插件
* @return
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
package com.zzg.config;
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.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import com.zzg.security.handler.UserAccessDeniedHandler;
import com.zzg.security.handler.UserLoginFailureHandler;
import com.zzg.security.handler.UserLoginSuccessHandler;
import com.zzg.security.handler.UserLogoutSuccessHandler;
import com.zzg.security.handler.UserNotLoginHandler;
import com.zzg.security.provider.UserAuthenticationProvider;
/**
* 系统安全核心配置
*
* @author zzg
*
*/
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig 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;
/**
* 加密方式
*
* @return
*/
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 用户登录验证
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(userAuthenticationProvider);
}
/**
* 安全权限配置
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers().frameOptions().sameOrigin() // 可以相同域名页面的frame中展示
.and().authorizeRequests().antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")//只有管理员才能访问
.antMatchers("/login", "/logout", "/layui/**","/jquery/**", "/images/**").permitAll()
.anyRequest().authenticated()//其他路径必须验证身份
.and().httpBasic().authenticationEntryPoint(userNotLoginHandler) // 配置未登录处理类
.and().formLogin().loginPage("/login").loginProcessingUrl("/api/login") // 配置登录URL
.successHandler(userLoginSuccessHandler) // 配置登录成功处理类
.failureHandler(userLoginFailureHandler) // 配置登录失败处理类
.and().exceptionHandling().accessDeniedHandler(userAccessDeniedHandler)// 配置没有权限处理类
.and().csrf().disable(); // 禁用跨站请求伪造防护
}
@Override
public void configure(WebSecurity web) throws Exception {
// TODO Auto-generated method stub
web.ignoring()
.antMatchers("/login")
.antMatchers("/logout")
.antMatchers("/static/**");
}
}
package com.zzg;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.zzg.mapper")
public class DemoApplication {
public static void main(String[] args) {
// TODO Auto-generated method stub
SpringApplication.run(DemoApplication.class, args);
}
}
9、SpringSecurity 处理器和认证提供者
package com.zzg.security.entity;
import java.io.Serializable;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import com.zzg.entity.User;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
public class MyUserDetails extends User implements org.springframework.security.core.userdetails.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;
}
}
package com.zzg.security.handler;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
/**
* 无权限处理类
*
* @author zzg
*
*/
@Component
public class UserAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.sendError(403);
}
}
package com.zzg.security.handler;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import com.zzg.common.Response;
/**
* 登录失败处理类
*
* @author zzg
*
*/
@Component
public class UserLoginFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
// TODO Auto-generated method stub
Response.responseJson(response, Response.error(500, "登录失败", exception.getMessage()));
}
}
package com.zzg.security.handler;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import com.zzg.common.Response;
/**
* 登录成功处理类
*
* @author zzg
*
*/
@Component
public class UserLoginSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
// TODO Auto-generated method stub
Response.responseJson(response, Response.success("登录成功"));
}
}
package com.zzg.security.handler;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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;
/**
* 登出成功处理类
*
* @author zzg
*
*/
@Component
public class UserLogoutSuccessHandler implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
SecurityContextHolder.clearContext();
response.sendRedirect("login");
}
}
package com.zzg.security.handler;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
/**
* 未登录处理类
*
* @author zzg
*
*/
@Component
public class UserNotLoginHandler implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
// TODO Auto-generated method stub
response.sendError(403);
}
}
package com.zzg.security.provider;
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.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component;
import com.zzg.security.entity.MyUserDetails;
import com.zzg.security.service.MyUserDetailService;
import cn.hutool.core.util.StrUtil;
/**
* 用户登录验证处理类
*
* @author zzg
*
*/
@Component
public class UserAuthenticationProvider implements AuthenticationProvider {
@Autowired
private MyUserDetailService userDetailsService;
/**
* 身份验证
*/
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// 获取用户名
String username = (String) authentication.getPrincipal();
// 获取密码
String password = (String) authentication.getCredentials();
MyUserDetails userDetails = (MyUserDetails) userDetailsService.loadUserByUsername(username);
if (userDetails == null) {
throw new UsernameNotFoundException("用户名不存在");
}
if (!StrUtil.equals(username, userDetails.getUsername())
|| !new BCryptPasswordEncoder().matches(password, userDetails.getPassword())) {
throw new BadCredentialsException("用户名或密码错误");
}
return new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
}
/**
* 支持指定的身份验证
*/
@Override
public boolean supports(Class<?> authentication) {
return true;
}
}
package com.zzg.security.service;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
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.Component;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zzg.entity.Role;
import com.zzg.entity.User;
import com.zzg.security.entity.MyUserDetails;
import com.zzg.service.RoleService;
import com.zzg.service.UserService;
@Component("MyUserDetailService")
public class MyUserDetailService implements UserDetailsService {
@Autowired
private UserService userService;
@Autowired
private RoleService roleService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// TODO Auto-generated method stub
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username", username);
User user = userService.getOne(queryWrapper);
if (user != null) {
MyUserDetails userDetails = new MyUserDetails();
BeanUtils.copyProperties(user, userDetails);
// 用户角色
Set<GrantedAuthority> authorities = new HashSet<>();
// 查询用户角色
List<Role> roleList = roleService.findByUserId(userDetails.getId());
roleList.forEach(role -> {
authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getRoleCode()));
});
userDetails.setAuthorities(authorities);
return userDetails;
}
return null;
}
}
10:源码下载地址
链接:https://pan.baidu.com/s/1fvxpzwPPFZbmERkgBPKOfA
提取码:zcxy