Commit f0b31a35 authored by dqjdda's avatar dqjdda
Browse files

security 优化,密码加密方式优化采用BCryptPasswordEncoder方式:SHA-256 +随机盐+密钥对密码进行加密

parent fe812f1c
package me.zhengjie.modules.security.service;
import me.zhengjie.modules.security.security.JwtUser;
import me.zhengjie.modules.security.security.OnlineUser;
import me.zhengjie.modules.security.config.SecurityProperties;
import me.zhengjie.modules.security.security.vo.JwtUser;
import me.zhengjie.modules.security.security.vo.OnlineUser;
import me.zhengjie.utils.EncryptUtils;
import me.zhengjie.utils.FileUtil;
import me.zhengjie.utils.PageUtil;
import me.zhengjie.utils.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
......@@ -26,18 +26,20 @@ import java.util.concurrent.TimeUnit;
@SuppressWarnings({"unchecked","all"})
public class OnlineUserService {
@Value("${jwt.expiration}")
private Long expiration;
@Value("${jwt.online}")
private String onlineKey;
private final SecurityProperties properties;
private final RedisTemplate redisTemplate;
public OnlineUserService(RedisTemplate redisTemplate) {
public OnlineUserService(SecurityProperties properties, RedisTemplate redisTemplate) {
this.properties = properties;
this.redisTemplate = redisTemplate;
}
/**
* 保存在线用户信息
* @param jwtUser
* @param token
* @param request
*/
public void save(JwtUser jwtUser, String token, HttpServletRequest request){
String job = jwtUser.getDept() + "/" + jwtUser.getJob();
String ip = StringUtils.getIp(request);
......@@ -49,10 +51,16 @@ public class OnlineUserService {
} catch (Exception e) {
e.printStackTrace();
}
redisTemplate.opsForValue().set(onlineKey + token, onlineUser);
redisTemplate.expire(onlineKey + token,expiration, TimeUnit.MILLISECONDS);
redisTemplate.opsForValue().set(properties.getOnlineKey() + token, onlineUser);
redisTemplate.expire(properties.getOnlineKey() + token,properties.getTokenValidityInSeconds(), TimeUnit.MILLISECONDS);
}
/**
* 查询全部数据
* @param filter
* @param pageable
* @return
*/
public Page<OnlineUser> getAll(String filter, Pageable pageable){
List<OnlineUser> onlineUsers = getAll(filter);
return new PageImpl<OnlineUser>(
......@@ -61,8 +69,13 @@ public class OnlineUserService {
onlineUsers.size());
}
/**
* 查询全部数据,不分页
* @param filter
* @return
*/
public List<OnlineUser> getAll(String filter){
List<String> keys = new ArrayList<>(redisTemplate.keys(onlineKey + "*"));
List<String> keys = new ArrayList<>(redisTemplate.keys(properties.getOnlineKey() + "*"));
Collections.reverse(keys);
List<OnlineUser> onlineUsers = new ArrayList<>();
for (String key : keys) {
......@@ -81,16 +94,31 @@ public class OnlineUserService {
return onlineUsers;
}
/**
* 踢出用户
* @param val
* @throws Exception
*/
public void kickOut(String val) throws Exception {
String key = onlineKey + EncryptUtils.desDecrypt(val);
String key = properties.getOnlineKey() + EncryptUtils.desDecrypt(val);
redisTemplate.delete(key);
}
/**
* 退出登录
* @param token
*/
public void logout(String token) {
String key = onlineKey + token;
String key = properties.getOnlineKey() + token;
redisTemplate.delete(key);
}
/**
* 导出
* @param all
* @param response
* @throws IOException
*/
public void download(List<OnlineUser> all, HttpServletResponse response) throws IOException {
List<Map<String, Object>> list = new ArrayList<>();
for (OnlineUser user : all) {
......@@ -105,4 +133,13 @@ public class OnlineUserService {
}
FileUtil.downloadExcel(list, response);
}
/**
* 查询用户
* @param key
* @return
*/
public OnlineUser getOne(String key) {
return (OnlineUser)redisTemplate.opsForValue().get(key);
}
}
package me.zhengjie.modules.security.service;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.security.security.JwtUser;
import me.zhengjie.modules.security.security.vo.JwtUser;
import me.zhengjie.modules.system.service.RoleService;
import me.zhengjie.modules.system.service.UserService;
import me.zhengjie.modules.system.service.dto.*;
import org.springframework.security.core.userdetails.UserDetails;
......@@ -15,31 +16,33 @@ import java.util.Optional;
* @author Zheng Jie
* @date 2018-11-22
*/
@Service
@Service("userDetailsService")
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class JwtUserDetailsServiceImpl implements UserDetailsService {
public class UserDetailsServiceImpl implements UserDetailsService {
private final UserService userService;
private final JwtPermissionServiceImpl permissionService;
private final RoleService roleService;
public JwtUserDetailsServiceImpl(UserService userService, JwtPermissionServiceImpl permissionService) {
public UserDetailsServiceImpl(UserService userService, RoleService roleService) {
this.userService = userService;
this.permissionService = permissionService;
this.roleService = roleService;
}
@Override
public UserDetails loadUserByUsername(String username){
UserDto user = userService.findByName(username);
if (user == null) {
throw new BadRequestException("账号不存在");
} else {
if (!user.getEnabled()) {
throw new BadRequestException("账号未激活");
}
return createJwtUser(user);
}
}
public UserDetails createJwtUser(UserDto user) {
private UserDetails createJwtUser(UserDto user) {
return new JwtUser(
user.getId(),
user.getUsername(),
......@@ -49,7 +52,7 @@ public class JwtUserDetailsServiceImpl implements UserDetailsService {
user.getPhone(),
Optional.ofNullable(user.getDept()).map(DeptSmallDto::getName).orElse(null),
Optional.ofNullable(user.getJob()).map(JobSmallDto::getName).orElse(null),
permissionService.mapToGrantedAuthorities(user),
roleService.mapToGrantedAuthorities(user),
user.getEnabled(),
user.getCreateTime(),
user.getLastPasswordResetTime()
......
package me.zhengjie.modules.security.utils;
import io.jsonwebtoken.*;
import io.jsonwebtoken.impl.DefaultClock;
import me.zhengjie.modules.security.security.JwtUser;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
/**
* @author /
*/
@Component
public class JwtTokenUtil implements Serializable {
private static final long serialVersionUID = -3301605591108950415L;
private Clock clock = DefaultClock.INSTANCE;
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private Long expiration;
@Value("${jwt.header}")
private String tokenHeader;
public String getUsernameFromToken(String token) {
return getClaimFromToken(token, Claims::getSubject);
}
private Date getIssuedAtDateFromToken(String token) {
return getClaimFromToken(token, Claims::getIssuedAt);
}
private Date getExpirationDateFromToken(String token) {
return getClaimFromToken(token, Claims::getExpiration);
}
private <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
final Claims claims = getAllClaimsFromToken(token);
return claimsResolver.apply(claims);
}
private Claims getAllClaimsFromToken(String token) {
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
}
private Boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(clock.now());
}
private Boolean isCreatedBeforeLastPasswordReset(Date created, Date lastPasswordReset) {
return (lastPasswordReset != null && created.before(lastPasswordReset));
}
private Boolean ignoreTokenExpiration(String token) {
// here you specify tokens, for that the expiration is ignored
return false;
}
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>(16);
return doGenerateToken(claims, userDetails.getUsername());
}
private String doGenerateToken(Map<String, Object> claims, String subject) {
final Date createdDate = clock.now();
final Date expirationDate = calculateExpirationDate(createdDate);
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(createdDate)
.setExpiration(expirationDate)
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
public Boolean canTokenBeRefreshed(String token, Date lastPasswordReset) {
final Date created = getIssuedAtDateFromToken(token);
return !isCreatedBeforeLastPasswordReset(created, lastPasswordReset)
&& (!isTokenExpired(token) || ignoreTokenExpiration(token));
}
public String refreshToken(String token) {
final Date createdDate = clock.now();
final Date expirationDate = calculateExpirationDate(createdDate);
final Claims claims = getAllClaimsFromToken(token);
claims.setIssuedAt(createdDate);
claims.setExpiration(expirationDate);
return Jwts.builder()
.setClaims(claims)
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
public String getToken(HttpServletRequest request){
final String requestHeader = request.getHeader(tokenHeader);
String startsWith = "Bearer ";
if (requestHeader != null && requestHeader.startsWith(startsWith)) {
return requestHeader.substring(7);
}
return null;
}
public Boolean validateToken(String token, UserDetails userDetails) {
JwtUser user = (JwtUser) userDetails;
final Date created = getIssuedAtDateFromToken(token);
// final Date expiration = getExpirationDateFromToken(token);
// 如果token存在,且token创建日期 > 最后修改密码的日期 则代表token有效
return (!isTokenExpired(token)
&& !isCreatedBeforeLastPasswordReset(created, user.getLastPasswordResetDate())
);
}
private Date calculateExpirationDate(Date createdDate) {
return new Date(createdDate.getTime() + expiration);
}
}
......@@ -5,6 +5,7 @@ import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
/**
* @author Zheng Jie
......@@ -36,9 +37,9 @@ public interface MenuRepository extends JpaRepository<Menu, Long>, JpaSpecificat
/**
* 根据角色ID与菜单类型查询菜单
* @param id roleID
* @param roleIds roleIDs
* @param type 类型
* @return /
*/
LinkedHashSet<Menu> findByRoles_IdAndTypeIsNotInOrderBySortAsc(Long id, Integer type);
LinkedHashSet<Menu> findByRoles_IdInAndTypeNotOrderBySortAsc(Set<Long> roleIds, int type);
}
......@@ -7,8 +7,10 @@ import me.zhengjie.aop.log.Log;
import me.zhengjie.modules.system.domain.Role;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.system.service.RoleService;
import me.zhengjie.modules.system.service.UserService;
import me.zhengjie.modules.system.service.dto.RoleQueryCriteria;
import me.zhengjie.modules.system.service.dto.RoleSmallDto;
import me.zhengjie.modules.system.service.dto.UserDto;
import me.zhengjie.utils.SecurityUtils;
import me.zhengjie.utils.ThrowableUtil;
import org.springframework.data.domain.Pageable;
......@@ -36,11 +38,13 @@ import java.util.stream.Collectors;
public class RoleController {
private final RoleService roleService;
private final UserService userService;
private static final String ENTITY_NAME = "role";
public RoleController(RoleService roleService) {
public RoleController(RoleService roleService, UserService userService) {
this.roleService = roleService;
this.userService = userService;
}
@ApiOperation("获取单个role")
......@@ -76,7 +80,8 @@ public class RoleController {
@ApiOperation("获取用户级别")
@GetMapping(value = "/level")
public ResponseEntity getLevel(){
List<Integer> levels = roleService.findByUsersId(SecurityUtils.getUserId()).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList());
UserDto user = userService.findByName(SecurityUtils.getUsername());
List<Integer> levels = roleService.findByUsersId(user.getId()).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList());
return new ResponseEntity<>(Dict.create().set("level", Collections.min(levels)),HttpStatus.OK);
}
......
......@@ -11,6 +11,7 @@ import me.zhengjie.modules.system.domain.vo.UserPassVo;
import me.zhengjie.modules.system.service.DeptService;
import me.zhengjie.modules.system.service.RoleService;
import me.zhengjie.modules.system.service.dto.RoleSmallDto;
import me.zhengjie.modules.system.service.dto.UserDto;
import me.zhengjie.modules.system.service.dto.UserQueryCriteria;
import me.zhengjie.service.VerificationCodeService;
import me.zhengjie.utils.*;
......@@ -20,6 +21,8 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.annotation.Validated;
......@@ -39,17 +42,15 @@ import java.util.stream.Collectors;
@RequestMapping("/api/users")
public class UserController {
private final PasswordEncoder passwordEncoder;
private final UserService userService;
private final DataScope dataScope;
private final DeptService deptService;
private final RoleService roleService;
private final VerificationCodeService verificationCodeService;
public UserController(UserService userService, DataScope dataScope, DeptService deptService, RoleService roleService, VerificationCodeService verificationCodeService) {
public UserController(PasswordEncoder passwordEncoder, UserService userService, DataScope dataScope, DeptService deptService, RoleService roleService, VerificationCodeService verificationCodeService) {
this.passwordEncoder = passwordEncoder;
this.userService = userService;
this.dataScope = dataScope;
this.deptService = deptService;
......@@ -123,7 +124,8 @@ public class UserController {
@DeleteMapping(value = "/{id}")
@PreAuthorize("@el.check('user:del')")
public ResponseEntity delete(@PathVariable Long id){
Integer currentLevel = Collections.min(roleService.findByUsersId(SecurityUtils.getUserId()).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList()));
UserDto user = userService.findByName(SecurityUtils.getUsername());
Integer currentLevel = Collections.min(roleService.findByUsersId(user.getId()).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList()));
Integer optLevel = Collections.min(roleService.findByUsersId(id).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList()));
if (currentLevel > optLevel) {
......@@ -135,15 +137,15 @@ public class UserController {
@ApiOperation("修改密码")
@PostMapping(value = "/updatePass")
public ResponseEntity updatePass(@RequestBody UserPassVo user){
UserDetails userDetails = SecurityUtils.getUserDetails();
if(!userDetails.getPassword().equals(EncryptUtils.encryptPassword(user.getOldPass()))){
public ResponseEntity updatePass(@RequestBody UserPassVo passVo){
UserDto user = userService.findByName(SecurityUtils.getUsername());
if(!passwordEncoder.matches(passVo.getOldPass(), user.getPassword())){
throw new BadRequestException("修改失败,旧密码错误");
}
if(userDetails.getPassword().equals(EncryptUtils.encryptPassword(user.getNewPass()))){
if(passwordEncoder.matches(passVo.getNewPass(), user.getPassword())){
throw new BadRequestException("新密码不能与旧密码相同");
}
userService.updatePass(userDetails.getUsername(),EncryptUtils.encryptPassword(user.getNewPass()));
userService.updatePass(user.getUsername(),passwordEncoder.encode(passVo.getNewPass()));
return new ResponseEntity(HttpStatus.OK);
}
......@@ -158,13 +160,13 @@ public class UserController {
@ApiOperation("修改邮箱")
@PostMapping(value = "/updateEmail/{code}")
public ResponseEntity updateEmail(@PathVariable String code,@RequestBody User user){
UserDetails userDetails = SecurityUtils.getUserDetails();
if(!userDetails.getPassword().equals(EncryptUtils.encryptPassword(user.getPassword()))){
UserDto userDto = userService.findByName(SecurityUtils.getUsername());
if(!passwordEncoder.matches(user.getPassword(), userDto.getPassword())){
throw new BadRequestException("密码错误");
}
VerificationCode verificationCode = new VerificationCode(code, ElAdminConstant.RESET_MAIL,"email",user.getEmail());
verificationCodeService.validated(verificationCode);
userService.updateEmail(userDetails.getUsername(),user.getEmail());
userService.updateEmail(userDto.getUsername(),user.getEmail());
return new ResponseEntity(HttpStatus.OK);
}
......@@ -173,7 +175,8 @@ public class UserController {
* @param resources /
*/
private void checkLevel(User resources) {
Integer currentLevel = Collections.min(roleService.findByUsersId(SecurityUtils.getUserId()).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList()));
UserDto user = userService.findByName(SecurityUtils.getUsername());
Integer currentLevel = Collections.min(roleService.findByUsersId(user.getId()).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList()));
Integer optLevel = roleService.findByRoles(resources.getRoles());
if (currentLevel > optLevel) {
throw new BadRequestException("角色权限不足");
......
......@@ -4,10 +4,14 @@ import me.zhengjie.modules.system.domain.Role;
import me.zhengjie.modules.system.service.dto.RoleDto;
import me.zhengjie.modules.system.service.dto.RoleQueryCriteria;
import me.zhengjie.modules.system.service.dto.RoleSmallDto;
import me.zhengjie.modules.system.service.dto.UserDto;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Pageable;
import org.springframework.security.core.GrantedAuthority;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Set;
......@@ -99,4 +103,11 @@ public interface RoleService {
* @throws IOException /
*/
void download(List<RoleDto> queryAll, HttpServletResponse response) throws IOException;
/**
* 获取用户权限信息
* @param user 用户信息
* @return 权限信息
*/
Collection<GrantedAuthority> mapToGrantedAuthorities(UserDto user);
}
......@@ -66,11 +66,8 @@ public class MenuServiceImpl implements MenuService {
@Override
public List<MenuDto> findByRoles(List<RoleSmallDto> roles) {
Set<Menu> menus = new LinkedHashSet<>();
for (RoleSmallDto role : roles) {
List<Menu> menus1 = new ArrayList<>(menuRepository.findByRoles_IdAndTypeIsNotInOrderBySortAsc(role.getId(), 2));
menus.addAll(menus1);
}
Set<Long> roleIds = roles.stream().map(RoleSmallDto::getId).collect(Collectors.toSet());
LinkedHashSet<Menu> menus = menuRepository.findByRoles_IdInAndTypeNotOrderBySortAsc(roleIds, 2);
return menus.stream().map(menuMapper::toDto).collect(Collectors.toList());
}
......
package me.zhengjie.modules.system.service.impl;
import me.zhengjie.modules.system.domain.Menu;
import me.zhengjie.modules.system.domain.Role;
import me.zhengjie.exception.EntityExistException;
import me.zhengjie.modules.system.repository.RoleRepository;
......@@ -7,17 +8,17 @@ import me.zhengjie.modules.system.service.RoleService;
import me.zhengjie.modules.system.service.dto.RoleDto;
import me.zhengjie.modules.system.service.dto.RoleQueryCriteria;
import me.zhengjie.modules.system.service.dto.RoleSmallDto;
import me.zhengjie.modules.system.service.dto.UserDto;
import me.zhengjie.modules.system.service.mapper.RoleMapper;
import me.zhengjie.modules.system.service.mapper.RoleSmallMapper;
import me.zhengjie.utils.FileUtil;
import me.zhengjie.utils.PageUtil;
import me.zhengjie.utils.QueryHelp;
import me.zhengjie.utils.ValidationUtil;
import me.zhengjie.utils.*;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
......@@ -144,6 +145,20 @@ public class RoleServiceImpl implements RoleService {
return Collections.min(roleDtos.stream().map(RoleDto::getLevel).collect(Collectors.toList()));
}
@Override
@Cacheable(key = "'loadPermissionByUser:' + #p0.username")
public Collection<GrantedAuthority> mapToGrantedAuthorities(UserDto user) {
Set<Role> roles = roleRepository.findByUsers_Id(user.getId());
Set<String> permissions = roles.stream().filter(role -> StringUtils.isNotBlank(role.getPermission())).map(Role::getPermission).collect(Collectors.toSet());
permissions.addAll(
roles.stream().flatMap(role -> role.getMenus().stream())
.filter(menu -> StringUtils.isNotBlank(menu.getPermission()))
.map(Menu::getPermission).collect(Collectors.toSet())
);
return permissions.stream().map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
}
@Override
public void download(List<RoleDto> roles, HttpServletResponse response) throws IOException {
List<Map<String, Object>> list = new ArrayList<>();
......
......@@ -2,7 +2,7 @@
spring:
datasource:
druid:
type: com.alibaba.druid.pool.DruidDataSource
db-type: com.alibaba.druid.pool.DruidDataSource
driverClassName: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
url: jdbc:log4jdbc:mysql://localhost:3306/eladmin?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false
username: root
......@@ -44,13 +44,18 @@ spring:
#jwt
jwt:
header: Authorization
secret: mySecret
# token 过期时间/毫秒,6小时 1小时 = 3600000 毫秒
expiration: 21600000
# 令牌前缀,主要最后留个空格
token-start-with: Bearer
# 必须使用最少88位的Base64对该令牌进行编码
base64-secret: ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI=
# 令牌过期时间 此处单位/秒 ,默认4小时
token-validity-in-seconds: 14400000
# 记住我模式下的令牌过期时间 此处单位/毫秒 ,默认1天
token-validity-in-seconds-for-remember-me: 86400000
# 在线用户key
online: online-token
online-key: online-token
# 验证码
codeKey: code-key
code-key: code-key
#是否允许生成代码,生产环境设置为false
generator:
......
......@@ -2,7 +2,7 @@
spring:
datasource:
druid:
type: com.alibaba.druid.pool.DruidDataSource
db-type: com.alibaba.druid.pool.DruidDataSource
driverClassName: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
url: jdbc:log4jdbc:mysql://localhost:3306/eladmin?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false
username: root
......@@ -46,13 +46,18 @@ spring:
#jwt
jwt:
header: Authorization
secret: mySecret
# token 过期时间 2个小时
expiration: 7200000
# 令牌前缀,主要最后留个空格
token-start-with: Bearer
# 必须使用最少88位的Base64对该令牌进行编码
base64-secret: ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI=
# 令牌过期时间 此处单位/秒 ,默认4小时
token-validity-in-seconds: 14400000
# 记住我模式下的令牌过期时间 此处单位/毫秒 ,默认1天
token-validity-in-seconds-for-remember-me: 86400000
# 在线用户key
online: online-token
online-key: online-token
# 验证码
codeKey: code-key
code-key: code-key
#是否允许生成代码,生产环境设置为false
generator:
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment