SpringBoot整合Security
pom
<!-- security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- jjwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- commons-collections4 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>${commons-collections4.version}</version>
</dependency>
<!-- commons-long3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
代码
SecurityConfig
Security的配置类想生效的自定义配置类都在这里配置生效
import com.alibaba.fastjson.JSONObject;
import com.monitor.conf.profile.ConfigProfileValue;
import com.monitor.conf.redis.RedisUtil;
import com.monitor.conf.result.Result;
import com.monitor.conf.result.ResultCodeEnum;
import com.monitor.conf.security.Handler.CustomAccessDecisionManager;
import com.monitor.conf.security.Handler.CustomAuthenticationProvider;
import com.monitor.conf.security.Handler.CustomFilterInvocationSecurityMetadataSource;
import com.monitor.conf.security.Handler.CustomAuthenticationSuccessHandler;
import com.monitor.conf.security.filter.JwtAuthorizationTokenFilter;
import com.monitor.constants.BaseConstant;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
/**
* @Author sm-liyujie
* @Date 2023/6/1 17:44
* @description: Security配置类
* @Version 1.0
*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 自定义登录成功处理器并生成token:响应状态码200及token
*/
@Resource
private CustomAuthenticationSuccessHandler authenticationSuccessHandler;
/**
* 自定义登录认证
*/
@Resource
private CustomAuthenticationProvider authenticationProvider;
/**
* 动态获取url权限配置
*/
@Resource
private CustomFilterInvocationSecurityMetadataSource filterInvocationSecurityMetadataSource;
/**
* 自定义权限判断管理器
*/
@Resource
private CustomAccessDecisionManager accessDecisionManager;
/**
* 身份验证详细信息源
*/
@Resource
private AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> authenticationDetailsSource;
/**
* JwtToken解析并生成authentication身份信息过滤器
*/
@Resource
private JwtAuthorizationTokenFilter authorizationTokenFilter;
@Resource
private RedisUtil redisUtil;
@Override
public void configure(WebSecurity web) {
//无条件允许访问
// web.ignoring().antMatchers("/command-record/getDiskResult");
}
@Override
protected void configure(AuthenticationManagerBuilder auth) {
//自定义登录认证
auth.authenticationProvider(authenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// 关闭csrf验证(防止跨站请求伪造攻击)
http.csrf().disable();
// JwtToken解析并生成authentication身份信息过滤器
http.addFilterBefore(authorizationTokenFilter, UsernamePasswordAuthenticationFilter.class);
// 未登录时:返回状态码401
http.exceptionHandling().authenticationEntryPoint(jsonAuthenticationEntryPoint());
// 无权访问时:返回状态码403
http.exceptionHandling().accessDeniedHandler(jsonAccessDeniedHandler());
// url权限认证处理
http.antMatcher("/**").authorizeRequests()
// .antMatchers("/security/user/**").hasRole("ADMIN") //需要ADMIN角色才可以访问
// .antMatchers("/connect").hasIpAddress("127.0.0.1") //只有ip[127.0.0.1]可以访问'/connect'接口
.anyRequest() //其他任何请求
.authenticated() //都需要身份认证
.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
@Override
public <O extends FilterSecurityInterceptor> O postProcess(O o) {
//动态获取url权限配置
o.setSecurityMetadataSource(filterInvocationSecurityMetadataSource);
//权限判断
o.setAccessDecisionManager(accessDecisionManager);
return o;
}
});
// 将session策略设置为无状态的,通过token进行登录认证
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// 开启自动配置的登录功能
http.formLogin()
//自定义登录请求路径(post)
.loginProcessingUrl("/nonceLogin")
//自定义登录用户名密码属性名,默认为username和password
.usernameParameter("username")
.passwordParameter("password")
//验证成功处理器(前后端分离):生成token及响应状态码200
.successHandler(authenticationSuccessHandler)
//验证失败处理器(前后端分离):返回状态码402
.failureHandler(jsonAuthenticationFailureHandler())
//登录验证中增加额外字段(验证码等等)
.authenticationDetailsSource(authenticationDetailsSource);
// 开启自动配置的注销功能
http.logout()
//自定义注销请求路径
.logoutUrl("/nonceLogout")
//注销成功处理器(前后端分离):返回状态码200
.logoutSuccessHandler(jsonLogoutSuccessHandler());
}
/**
* 自定义登录失败处理器:返回状态码402
* @return
*/
private AuthenticationFailureHandler jsonAuthenticationFailureHandler() {
return (request, response, e) -> {
response.setContentType("application/json;charset=utf-8");
Result result = Result.builder()
.code("402")
.message(e.getMessage())
.build();
response.setStatus(402);
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write(JSONObject.toJSONString(result));
};
}
/**
* 自定义权限不足处理器:返回状态码403
* @return
*/
private AccessDeniedHandler jsonAccessDeniedHandler() {
return (request, response, e) -> {
response.setContentType("application/json;charset=utf-8");
Result result = Result.builder()
.code("403")
.errorstack(e.getMessage())
.message("权限不足")
.build();
response.setStatus(403);
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write(JSONObject.toJSONString(result));
};
}
/**
* 自定义未登录时处理器:返回状态码401
* @return
*/
private AuthenticationEntryPoint jsonAuthenticationEntryPoint() {
return (request, response, e) -> {
response.setContentType("application/json;charset=utf-8");
Result result = Result.builder()
.code("401")
.errorstack(e.getMessage())
.message("用户未登录")
.build();
response.setStatus(401);
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write(JSONObject.toJSONString(result));
};
}
/**
* 自定义注销成功处理器:返回状态码200
* @return
*/
private LogoutSuccessHandler jsonLogoutSuccessHandler() {
return (request, response, e) -> {
String token = request.getHeader(ConfigProfileValue.tokenHeaderKey);
redisUtil.del(BaseConstant.REDIS_LOGIN_TOKEN_KEY + token);
response.setContentType("application/json;charset=utf-8");
Result result = Result.builder()
.code(ResultCodeEnum.SUCCESS.getCode())
.message("注销成功")
.build();
response.setStatus(200);
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write(JSONObject.toJSONString(result));
};
}
}
CustomAuthenticationProvider
自定义登录认证(判断账号密码,启用禁用等等)
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.monitor.conf.redis.RedisUtil;
import com.monitor.conf.security.server.CustomUserDetails;
import com.monitor.conf.security.server.CustomUserDetailsService;
import com.monitor.constants.BaseConstant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @Author sm-liyujie
* @Date 2023/6/2 9:24
* @description: 自定义登录认证
* @Version 1.0
*/
@Component
@Slf4j
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Resource
private CustomUserDetailsService userDetailsService;
@Resource
private RedisUtil redisUtil;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
log.info("authentication >> {}", JSONObject.toJSONString(authentication, SerializerFeature.WriteMapNullValue));
//登录接口自定义字段(除了账号密码)
CustomWebAuthenticationDetails customWebAuthenticationDetails = (CustomWebAuthenticationDetails) authentication.getDetails();
//verifyCode测试字段(可以放验证码之类的信息)
System.out.println("verifyCode >> " + customWebAuthenticationDetails.getVerifyCode());
//表单输入的用户名
String username = (String) authentication.getPrincipal();
//表单输入的密码
String password = (String) authentication.getCredentials();
//根据Username获取用户
CustomUserDetails userInfo = (CustomUserDetails) userDetailsService.loadUserByUsername(username);
//校验用户名密码
boolean matches = new BCryptPasswordEncoder().matches(password, userInfo.getPassword());
if (!matches) {
throw new BadCredentialsException("账号或密码错误");
}
if (!userInfo.isEnabled()) {
throw new DisabledException("账号被禁用");
}
if (CollectionUtils.isEmpty(userInfo.getAuthorities())){
throw new InsufficientAuthenticationException("用户无角色");
}
//存入redis 用户信息
userInfo.setPassword(null);
redisUtil.set(BaseConstant.USER_DETAILS_KEY + username,userInfo);
//返回用户认证
return new UsernamePasswordAuthenticationToken(username, userInfo.getPassword(), userInfo.getAuthorities());
}
@Override
public boolean supports(Class<?> authentication) {
return true;
}
}
CustomUserDetails
security的用户对象
import com.monitor.conf.result.BaseEntity;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
/**
* @Author sm-liyujie
* @Date 2023/6/2 11:02
* @description: security的用户对象
* @Version 1.0
*/
@Data
public class CustomUserDetails extends BaseEntity implements UserDetails {
/**
* 用户名
*/
private String username;
/**
* 昵称
*/
private String nickName;
/**
* 密码
*/
private String password;
/**
* 邮箱
*/
private String email;
/**
* 手机号
*/
private String phone;
/**
* 0禁用 1启用
*/
private Integer enable;
/**
* 通过springSecurity进行授权
*/
private Collection<? extends GrantedAuthority> authorities;
private Boolean enabled;
private Boolean accountNonExpired;
private Boolean credentialsNonExpired;
private Boolean accountNonLocked;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return enable == 1;
}
}
CustomUserDetailsService
自定义用户认证,通过username去数据库获取用户并转化为CustomUserDetails
import com.monitor.modules.user.entity.model.SysUser;
import com.monitor.modules.user.service.SysUserService;
import com.monitor.utils.CopyUtil;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @Author sm-liyujie
* @Date 2023/6/1 17:56
* @description: 自定义用户认证
* @Version 1.0
*/
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Resource
private SysUserService userService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//登录名获取用户(数据库)
SysUser sysUser = userService.findUserByUserName(username);
if (sysUser == null){
throw new UsernameNotFoundException("User name" + username + "not find!!");
}
//对象拷贝
CustomUserDetails userInfo = CopyUtil.copy(sysUser, CustomUserDetails.class);
//用户角色集合
Set<SimpleGrantedAuthority> authoritiesSet = new HashSet<>();
//获取用户角色
List<String> roles = userService.findRoleNameByUsername(sysUser.getId());
for (String roleName : roles) {
//用户拥有的角色
SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(roleName);
authoritiesSet.add(simpleGrantedAuthority);
}
userInfo.setAuthorities(authoritiesSet);
return userInfo;
}
}
CustomWebAuthenticationDetails
登录自定义字段
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
/**
* @Author sm-liyujie
* @Date 2023/6/2 9:38
* @description: 登录自定义字段
* @Version 1.0
*/
public class CustomWebAuthenticationDetails extends WebAuthenticationDetails implements Serializable {
private String verifyCode;
CustomWebAuthenticationDetails(HttpServletRequest httpServletRequest) {
super(httpServletRequest);
verifyCode = httpServletRequest.getParameter("verifyCode");
}
String getVerifyCode() {
return verifyCode;
}
}
CustomAuthenticationSuccessHandler
自定义登录成功处理器:返回状态码200
import com.alibaba.fastjson.JSONObject;
import com.monitor.conf.profile.ConfigProfileValue;
import com.monitor.conf.redis.RedisUtil;
import com.monitor.conf.result.Result;
import com.monitor.conf.result.ResultCodeEnum;
import com.monitor.conf.security.server.CustomUserDetails;
import com.monitor.constants.BaseConstant;
import com.monitor.utils.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @Author sm-liyujie
* @Date 2023/6/2 9:23
* @description: 自定义登录成功处理器:返回状态码200
* @Version 1.0
*/
@Component
@Slf4j
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Resource
private RedisUtil redisUtil;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
response.setCharacterEncoding("UTF-8");
//这里也可以用map代替(返回的对象)
Result result = Result.builder()
.code(ResultCodeEnum.SUCCESS.getCode())
.message("登录成功")
.build();
//表单输入的用户名
String username = (String) authentication.getPrincipal();
//用户角色
List<String> role = authentication.getAuthorities()
.stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toList());
// 生成token并设置响应头
Map<String,Object> claims = new HashMap<>();
claims.put("username",username);
claims.put("role", role);
String token = JwtUtil.generate(username,claims);
//存入redis token
redisUtil.set(BaseConstant.REDIS_LOGIN_TOKEN_KEY + token, token, ConfigProfileValue.tokenExpiration);
//设置token响应头
response.addHeader(ConfigProfileValue.tokenHeaderKey, token);
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write(JSONObject.toJSONString(result));
}
}
CustomFilterInvocationSecurityMetadataSource
动态获取url权限配置:将角色和权限进行绑定
import com.monitor.modules.user.service.SysRoleService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @Author sm-liyujie
* @Date 2023/6/2 9:25
* @description: 动态获取url权限配置
* @Version 1.0
*/
@Component
@Slf4j
public class CustomFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
@Resource
private SysRoleService roleService;
@Override
public Collection<ConfigAttribute> getAttributes(Object o) {
Set<ConfigAttribute> set = new HashSet<>();
// 获取请求地址
String requestUrl = ((FilterInvocation) o).getRequestUrl();
log.info("requestUrl >> {}", requestUrl);
//获取接口需要的权限
List<String> roleNames = roleService.findRoleNameByMenuUrl(requestUrl);
if (CollectionUtils.isNotEmpty(roleNames)){
//设置权限
roleNames.forEach(roleName -> {
SecurityConfig securityConfig = new SecurityConfig(roleName);
set.add(securityConfig);
});
}
//没有配置默认登录权限
if (CollectionUtils.isEmpty(roleNames)) {
return SecurityConfig.createList("ROLE_LOGIN");
}
return set;
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
@Override
public boolean supports(Class<?> aClass) {
return FilterInvocation.class.isAssignableFrom(aClass);
}
}
CustomAccessDecisionManager
自定义权限判断管理器:根据上面角色绑定的权限,看下当前登录用户有没有请求的接口需要的角色
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;
import java.util.Collection;
/**
* @Author sm-liyujie
* @Date 2023/6/2 9:25
* @description: 自定义权限判断管理器
* @Version 1.0
*/
@Component
@Slf4j
public class CustomAccessDecisionManager implements AccessDecisionManager {
@Override
public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> collection) throws AccessDeniedException, InsufficientAuthenticationException {
// 当前请求需要的权限
log.info("collection:{}", collection);
// 当前用户所具有的权限
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
log.info("principal:{} authorities:{}", authentication.getPrincipal().toString(), authorities);
for (ConfigAttribute configAttribute : collection) {
// 当前请求需要的权限
String needRole = configAttribute.getAttribute();
if ("ROLE_LOGIN".equals(needRole)) {
if (authentication instanceof AnonymousAuthenticationToken) {
throw new BadCredentialsException("Not logged in!!");
} else {
return;
}
}
// 当前用户所具有的权限
for (GrantedAuthority grantedAuthority : authorities) {
// 包含其中一个角色即可访问
if (grantedAuthority.getAuthority().equals(needRole)) {
return;
}
}
}
throw new AccessDeniedException("SimpleGrantedAuthority!!");
}
@Override
public boolean supports(ConfigAttribute configAttribute) {
return true;
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
JwtAuthorizationTokenFilter
JwtToken解析并生成authentication身份信息过滤器
拦截器验证token
import com.alibaba.fastjson.JSONObject;
import com.monitor.conf.profile.ConfigProfileValue;
import com.monitor.conf.redis.RedisUtil;
import com.monitor.conf.result.Result;
import com.monitor.constants.BaseConstant;
import com.monitor.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;
/**
* @Author sm-liyujie
* @Date 2023/6/2 9:26
* @description: JwtToken解析并生成authentication身份信息过滤器
* @Version 1.0
*/
@Component
@Slf4j
public class JwtAuthorizationTokenFilter extends OncePerRequestFilter {
@Resource
private RedisUtil redisUtil;
/**
* 解析token并生成authentication身份信息
* @param request
* @param response
* @param chain
* @throws ServletException
* @throws IOException
*/
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException {
try {
String token = request.getHeader(ConfigProfileValue.tokenHeaderKey);
log.info("JwtAuthorizationTokenFilter >> token:{}", token);
//查看token是否存在
String loginKey = BaseConstant.REDIS_LOGIN_TOKEN_KEY + token;
String currentToken = (String) redisUtil.get(loginKey);
if (null == token || !token.startsWith(ConfigProfileValue.tokenPrefix) || currentToken == null) {
chain.doFilter(request, response);
return;
}
// 解析token
Claims claims = JwtUtil.getClaim(token);
if (claims == null){
chain.doFilter(request, response);
return;
}
String username = (String) claims.get("username");
List<String> roles = claims.get("role", List.class);
List<SimpleGrantedAuthority> authorities = roles.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
if (StringUtils.isNotEmpty(username)) {
// 生成authentication身份信息
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, null, authorities);
SecurityContextHolder.getContext().setAuthentication(authentication);
//刷新token时间
redisUtil.expire(loginKey,ConfigProfileValue.tokenExpiration);
}
chain.doFilter(request, response);
} catch (Exception e) {
log.error("token校验拦截器异常:" + e.getMessage());
response.setContentType("application/json;charset=utf-8");
Result result = Result.builder()
.code("500")
.message(e.getMessage())
.build();
response.setStatus(500);
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write(JSONObject.toJSONString(result));
}
}
}
数据库结构
-- ----------------------------
-- Table structure for sys_menu
-- ----------------------------
DROP TABLE IF EXISTS `sys_menu`;
CREATE TABLE `sys_menu` (
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
`url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '请求路径',
`menu_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '菜单名称',
`parent_id` bigint NULL DEFAULT NULL COMMENT '父菜单id',
`url_pre` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '路由(前端自己匹配用)',
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
`operator` bigint NOT NULL DEFAULT -1 COMMENT '操作人',
`is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除:0是 1否',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
`role_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色名称',
`role_name_cn` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '角色名称中文',
`role_desc` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '角色描述',
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
`operator` bigint NOT NULL DEFAULT -1 COMMENT '操作人',
`is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除:0是 1否',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for sys_role_menu
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_menu`;
CREATE TABLE `sys_role_menu` (
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
`role_id` bigint NOT NULL COMMENT '角色id',
`menu_id` bigint NOT NULL COMMENT '菜单id',
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
`operator` bigint NOT NULL DEFAULT -1 COMMENT '操作人',
`is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除:0是 1否',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
`username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户名',
`nick_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '昵称',
`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '密码',
`email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱',
`phone` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '手机号',
`enable` tinyint(1) NOT NULL DEFAULT 1 COMMENT '0禁用 1启用',
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
`operator` bigint NOT NULL DEFAULT -1 COMMENT '操作人',
`is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除:0是 1否',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` bigint NOT NULL COMMENT '用户id',
`role_id` bigint NOT NULL COMMENT '角色id',
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
`operator` bigint NOT NULL DEFAULT -1 COMMENT '操作人',
`is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除:0是 1否',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;