mirror of https://github.com/elunez/eladmin
security 优化,密码加密方式优化采用BCryptPasswordEncoder方式:SHA-256 +随机盐+密钥对密码进行加密
parent
fe812f1c88
commit
f0b31a357c
|
@ -39,6 +39,9 @@ public class SwaggerConfig {
|
|||
@Value("${jwt.header}")
|
||||
private String tokenHeader;
|
||||
|
||||
@Value("${jwt.token-start-with}")
|
||||
private String tokenStartWith;
|
||||
|
||||
@Value("${swagger.enabled}")
|
||||
private Boolean enabled;
|
||||
|
||||
|
@ -50,7 +53,7 @@ public class SwaggerConfig {
|
|||
ticketPar.name(tokenHeader).description("token")
|
||||
.modelRef(new ModelRef("string"))
|
||||
.parameterType("header")
|
||||
.defaultValue("Bearer ")
|
||||
.defaultValue(tokenStartWith + " ")
|
||||
.required(true)
|
||||
.build();
|
||||
pars.add(ticketPar.build());
|
||||
|
|
|
@ -82,11 +82,4 @@ public class EncryptUtils {
|
|||
}
|
||||
return b2;
|
||||
}
|
||||
|
||||
/**
|
||||
* 密码加密
|
||||
*/
|
||||
public static String encryptPassword(String password){
|
||||
return DigestUtils.md5DigestAsHex(password.getBytes());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package me.zhengjie.utils;
|
|||
import cn.hutool.json.JSONObject;
|
||||
import me.zhengjie.exception.BadRequestException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
/**
|
||||
|
@ -15,7 +16,7 @@ public class SecurityUtils {
|
|||
public static UserDetails getUserDetails() {
|
||||
UserDetails userDetails;
|
||||
try {
|
||||
userDetails = (UserDetails) org.springframework.security.core.context.SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
} catch (Exception e) {
|
||||
throw new BadRequestException(HttpStatus.UNAUTHORIZED, "登录状态过期");
|
||||
}
|
||||
|
@ -30,13 +31,4 @@ public class SecurityUtils {
|
|||
Object obj = getUserDetails();
|
||||
return new JSONObject(obj).get("username", String.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统用户id
|
||||
* @return 系统用户id
|
||||
*/
|
||||
public static Long getUserId(){
|
||||
Object obj = getUserDetails();
|
||||
return new JSONObject(obj).get("id", Long.class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<name>核心模块</name>
|
||||
|
||||
<properties>
|
||||
<jjwt.version>0.9.1</jjwt.version>
|
||||
<jjwt.version>0.10.6</jjwt.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@ -45,7 +45,17 @@
|
|||
<!--jwt-->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
<artifactId>jjwt-api</artifactId>
|
||||
<version>${jjwt.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-impl</artifactId>
|
||||
<version>${jjwt.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-jackson</artifactId>
|
||||
<version>${jjwt.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package me.zhengjie.modules.monitor.service.impl;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import me.zhengjie.modules.monitor.domain.vo.RedisVo;
|
||||
import me.zhengjie.modules.monitor.service.RedisService;
|
||||
import me.zhengjie.modules.security.config.SecurityProperties;
|
||||
import me.zhengjie.utils.FileUtil;
|
||||
import me.zhengjie.utils.PageUtil;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
@ -27,18 +27,13 @@ import java.util.stream.Collectors;
|
|||
public class RedisServiceImpl implements RedisService {
|
||||
|
||||
private final RedisTemplate redisTemplate;
|
||||
|
||||
private final SecurityProperties properties;
|
||||
@Value("${loginCode.expiration}")
|
||||
private Long expiration;
|
||||
|
||||
@Value("${jwt.online}")
|
||||
private String onlineKey;
|
||||
|
||||
@Value("${jwt.codeKey}")
|
||||
private String codeKey;
|
||||
|
||||
public RedisServiceImpl(RedisTemplate redisTemplate) {
|
||||
public RedisServiceImpl(RedisTemplate redisTemplate, SecurityProperties properties) {
|
||||
this.redisTemplate = redisTemplate;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -59,7 +54,7 @@ public class RedisServiceImpl implements RedisService {
|
|||
Set<String> keys = redisTemplate.keys(key);
|
||||
for (String s : keys) {
|
||||
// 过滤掉权限的缓存
|
||||
if (s.contains("role::loadPermissionByUser") || s.contains("user::loadUserByUsername") || s.contains(onlineKey) || s.contains(codeKey)) {
|
||||
if (s.contains("role::loadPermissionByUser") || s.contains("user::loadUserByUsername") || s.contains(properties.getOnlineKey()) || s.contains(properties.getCodeKey())) {
|
||||
continue;
|
||||
}
|
||||
RedisVo redisVo = new RedisVo(s, Objects.requireNonNull(redisTemplate.opsForValue().get(s)).toString());
|
||||
|
@ -76,7 +71,7 @@ public class RedisServiceImpl implements RedisService {
|
|||
@Override
|
||||
public void deleteAll() {
|
||||
Set<String> keys = redisTemplate.keys( "*");
|
||||
redisTemplate.delete(keys.stream().filter(s -> !s.contains(onlineKey)).filter(s -> !s.contains(codeKey)).collect(Collectors.toList()));
|
||||
redisTemplate.delete(keys.stream().filter(s -> !s.contains(properties.getOnlineKey())).filter(s -> !s.contains(properties.getCodeKey())).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,19 +1,12 @@
|
|||
package me.zhengjie.modules.security.config;
|
||||
|
||||
import me.zhengjie.annotation.AnonymousAccess;
|
||||
import me.zhengjie.modules.security.security.JwtAccessDeniedHandler;
|
||||
import me.zhengjie.modules.security.security.JwtAuthenticationEntryPoint;
|
||||
import me.zhengjie.modules.security.security.JwtAuthorizationTokenFilter;
|
||||
import me.zhengjie.modules.security.service.JwtUserDetailsServiceImpl;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import me.zhengjie.modules.security.security.*;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
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;
|
||||
|
@ -23,6 +16,7 @@ import org.springframework.security.config.http.SessionCreationPolicy;
|
|||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||
|
@ -35,38 +29,23 @@ import java.util.Set;
|
|||
*/
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
|
||||
public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
private final JwtAuthenticationEntryPoint unauthorizedHandler;
|
||||
|
||||
private final JwtAccessDeniedHandler accessDeniedHandler;
|
||||
|
||||
private final JwtUserDetailsServiceImpl jwtUserDetailsService;
|
||||
|
||||
private final TokenProvider tokenProvider;
|
||||
private final CorsFilter corsFilter;
|
||||
private final JwtAuthenticationEntryPoint authenticationErrorHandler;
|
||||
private final JwtAccessDeniedHandler jwtAccessDeniedHandler;
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
/** 自定义基于JWT的安全过滤器 */
|
||||
private final JwtAuthorizationTokenFilter authenticationTokenFilter;
|
||||
|
||||
@Value("${jwt.header}")
|
||||
private String tokenHeader;
|
||||
|
||||
public SecurityConfig(JwtAuthenticationEntryPoint unauthorizedHandler, JwtAccessDeniedHandler accessDeniedHandler, JwtUserDetailsServiceImpl jwtUserDetailsService, JwtAuthorizationTokenFilter authenticationTokenFilter, ApplicationContext applicationContext) {
|
||||
this.unauthorizedHandler = unauthorizedHandler;
|
||||
this.accessDeniedHandler = accessDeniedHandler;
|
||||
this.jwtUserDetailsService = jwtUserDetailsService;
|
||||
this.authenticationTokenFilter = authenticationTokenFilter;
|
||||
public SecurityConfig(TokenProvider tokenProvider, CorsFilter corsFilter, JwtAuthenticationEntryPoint authenticationErrorHandler, JwtAccessDeniedHandler jwtAccessDeniedHandler, ApplicationContext applicationContext) {
|
||||
this.tokenProvider = tokenProvider;
|
||||
this.corsFilter = corsFilter;
|
||||
this.authenticationErrorHandler = authenticationErrorHandler;
|
||||
this.jwtAccessDeniedHandler = jwtAccessDeniedHandler;
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.userDetailsService(jwtUserDetailsService)
|
||||
.passwordEncoder(passwordEncoderBean());
|
||||
}
|
||||
|
||||
@Bean
|
||||
GrantedAuthorityDefaults grantedAuthorityDefaults() {
|
||||
// Remove the ROLE_ prefix
|
||||
|
@ -74,16 +53,10 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
|||
}
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoderBean() {
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean() throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity httpSecurity) throws Exception {
|
||||
// 搜寻 匿名标记 url: PreAuthorize("hasAnyRole('anonymous')") 和 PreAuthorize("@el.check('anonymous')") 和 AnonymousAccess
|
||||
|
@ -102,12 +75,25 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
|||
httpSecurity
|
||||
// 禁用 CSRF
|
||||
.csrf().disable()
|
||||
|
||||
.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
|
||||
// 授权异常
|
||||
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
|
||||
.exceptionHandling().accessDeniedHandler(accessDeniedHandler).and()
|
||||
.exceptionHandling()
|
||||
.authenticationEntryPoint(authenticationErrorHandler)
|
||||
.accessDeniedHandler(jwtAccessDeniedHandler)
|
||||
|
||||
// 防止iframe 造成跨域
|
||||
.and()
|
||||
.headers()
|
||||
.frameOptions()
|
||||
.sameOrigin()
|
||||
|
||||
// 不创建会话
|
||||
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
|
||||
// 过滤请求
|
||||
.and()
|
||||
.sessionManagement()
|
||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
||||
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.antMatchers(
|
||||
HttpMethod.GET,
|
||||
|
@ -116,7 +102,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
|||
"/**/*.css",
|
||||
"/**/*.js",
|
||||
"/webSocket/**"
|
||||
).anonymous()
|
||||
).permitAll()
|
||||
// swagger start
|
||||
.antMatchers("/swagger-ui.html").permitAll()
|
||||
.antMatchers("/swagger-resources/**").permitAll()
|
||||
|
@ -126,16 +112,18 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
|||
// 文件
|
||||
.antMatchers("/avatar/**").permitAll()
|
||||
.antMatchers("/file/**").permitAll()
|
||||
.antMatchers("/druid/**").permitAll()
|
||||
// 放行OPTIONS请求
|
||||
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
|
||||
.antMatchers("/druid/**").permitAll()
|
||||
// 自定义匿名访问所有url放行 : 允许 匿名和带权限以及登录用户访问
|
||||
.antMatchers(anonymousUrls.toArray(new String[0])).permitAll()
|
||||
// 所有请求都需要认证
|
||||
.anyRequest().authenticated()
|
||||
// 防止iframe 造成跨域
|
||||
.and().headers().frameOptions().disable();
|
||||
httpSecurity
|
||||
.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
.and()
|
||||
.apply(securityConfigurerAdapter());
|
||||
}
|
||||
|
||||
private TokenConfigurer securityConfigurerAdapter() {
|
||||
return new TokenConfigurer(tokenProvider);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
package me.zhengjie.modules.security.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Jwt参数配置
|
||||
* @author Zheng Jie
|
||||
* @date 2019年11月28日
|
||||
*/
|
||||
@Data
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "jwt")
|
||||
public class SecurityProperties {
|
||||
|
||||
/** Request Headers : Authorization */
|
||||
private String header;
|
||||
|
||||
/** 令牌前缀,最后留个空格 Bearer */
|
||||
private String tokenStartWith;
|
||||
|
||||
/** 必须使用最少88位的Base64对该令牌进行编码 */
|
||||
private String base64Secret;
|
||||
|
||||
/** 令牌过期时间 此处单位/秒 */
|
||||
private Long tokenValidityInSeconds;
|
||||
|
||||
/** 记住我模式下的令牌过期时间 此处单位/毫秒 */
|
||||
private Long tokenValidityInSecondsForRememberMe;
|
||||
|
||||
/** 在线用户 key,根据 key 查询 redis 中在线用户的数据 */
|
||||
private String onlineKey;
|
||||
|
||||
/** 验证码 key */
|
||||
private String codeKey;
|
||||
|
||||
public String getTokenStartWith() {
|
||||
return tokenStartWith + " ";
|
||||
}
|
||||
}
|
|
@ -9,24 +9,25 @@ import me.zhengjie.annotation.AnonymousAccess;
|
|||
import me.zhengjie.aop.log.Log;
|
||||
import me.zhengjie.exception.BadRequestException;
|
||||
import me.zhengjie.modules.monitor.service.RedisService;
|
||||
import me.zhengjie.modules.security.security.AuthInfo;
|
||||
import me.zhengjie.modules.security.security.AuthUser;
|
||||
import me.zhengjie.modules.security.security.ImgResult;
|
||||
import me.zhengjie.modules.security.security.JwtUser;
|
||||
import me.zhengjie.modules.security.config.SecurityProperties;
|
||||
import me.zhengjie.modules.security.security.TokenProvider;
|
||||
import me.zhengjie.modules.security.security.vo.AuthUser;
|
||||
import me.zhengjie.modules.security.security.vo.JwtUser;
|
||||
import me.zhengjie.modules.security.service.OnlineUserService;
|
||||
import me.zhengjie.utils.EncryptUtils;
|
||||
import me.zhengjie.modules.security.utils.JwtTokenUtil;
|
||||
import me.zhengjie.utils.SecurityUtils;
|
||||
import me.zhengjie.utils.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.authentication.AccountExpiredException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
|
@ -37,24 +38,22 @@ import javax.servlet.http.HttpServletRequest;
|
|||
@RestController
|
||||
@RequestMapping("/auth")
|
||||
@Api(tags = "系统:系统授权接口")
|
||||
public class AuthenticationController {
|
||||
|
||||
@Value("${jwt.codeKey}")
|
||||
private String codeKey;
|
||||
|
||||
private final JwtTokenUtil jwtTokenUtil;
|
||||
public class AuthController {
|
||||
|
||||
private final SecurityProperties properties;
|
||||
private final RedisService redisService;
|
||||
|
||||
private final UserDetailsService userDetailsService;
|
||||
|
||||
private final OnlineUserService onlineUserService;
|
||||
private final TokenProvider tokenProvider;
|
||||
private final AuthenticationManagerBuilder authenticationManagerBuilder;
|
||||
|
||||
public AuthenticationController(JwtTokenUtil jwtTokenUtil, RedisService redisService, @Qualifier("jwtUserDetailsServiceImpl") UserDetailsService userDetailsService, OnlineUserService onlineUserService) {
|
||||
this.jwtTokenUtil = jwtTokenUtil;
|
||||
public AuthController(SecurityProperties properties, RedisService redisService, UserDetailsService userDetailsService, OnlineUserService onlineUserService, TokenProvider tokenProvider, AuthenticationManagerBuilder authenticationManagerBuilder) {
|
||||
this.properties = properties;
|
||||
this.redisService = redisService;
|
||||
this.userDetailsService = userDetailsService;
|
||||
this.onlineUserService = onlineUserService;
|
||||
this.tokenProvider = tokenProvider;
|
||||
this.authenticationManagerBuilder = authenticationManagerBuilder;
|
||||
}
|
||||
|
||||
@Log("用户登录")
|
||||
|
@ -62,7 +61,6 @@ public class AuthenticationController {
|
|||
@AnonymousAccess
|
||||
@PostMapping(value = "/login")
|
||||
public ResponseEntity login(@Validated @RequestBody AuthUser authUser, HttpServletRequest request){
|
||||
|
||||
// 查询验证码
|
||||
String code = redisService.getCodeVal(authUser.getUuid());
|
||||
// 清除验证码
|
||||
|
@ -73,21 +71,23 @@ public class AuthenticationController {
|
|||
if (StringUtils.isBlank(authUser.getCode()) || !authUser.getCode().equalsIgnoreCase(code)) {
|
||||
throw new BadRequestException("验证码错误");
|
||||
}
|
||||
final JwtUser jwtUser = (JwtUser) userDetailsService.loadUserByUsername(authUser.getUsername());
|
||||
UsernamePasswordAuthenticationToken authenticationToken =
|
||||
new UsernamePasswordAuthenticationToken(authUser.getUsername(), authUser.getPassword());
|
||||
|
||||
if(!jwtUser.getPassword().equals(EncryptUtils.encryptPassword(authUser.getPassword()))){
|
||||
throw new AccountExpiredException("密码错误");
|
||||
}
|
||||
|
||||
if(!jwtUser.isEnabled()){
|
||||
throw new AccountExpiredException("账号已停用,请联系管理员");
|
||||
}
|
||||
Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
boolean rememberMe = (authUser.getRememberMe() == null) ? false : authUser.getRememberMe();
|
||||
// 生成令牌
|
||||
final String token = jwtTokenUtil.generateToken(jwtUser);
|
||||
String token = tokenProvider.createToken(authentication, rememberMe);
|
||||
final JwtUser jwtUser = (JwtUser) authentication.getPrincipal();
|
||||
// 保存在线信息
|
||||
onlineUserService.save(jwtUser, token, request);
|
||||
// 返回 token
|
||||
return ResponseEntity.ok(new AuthInfo(token,jwtUser));
|
||||
// 返回 token 与 用户信息
|
||||
Map<String,Object> authInfo = new HashMap<String,Object>(2){{
|
||||
put("token", properties.getTokenStartWith() + token);
|
||||
put("user", jwtUser);
|
||||
}};
|
||||
return ResponseEntity.ok(authInfo);
|
||||
}
|
||||
|
||||
@ApiOperation("获取用户信息")
|
||||
|
@ -100,23 +100,28 @@ public class AuthenticationController {
|
|||
@ApiOperation("获取验证码")
|
||||
@AnonymousAccess
|
||||
@GetMapping(value = "/code")
|
||||
public ImgResult getCode(){
|
||||
public ResponseEntity getCode(){
|
||||
// 算术类型 https://gitee.com/whvse/EasyCaptcha
|
||||
ArithmeticCaptcha captcha = new ArithmeticCaptcha(111, 36);
|
||||
// 几位数运算,默认是两位
|
||||
captcha.setLen(2);
|
||||
// 获取运算的结果:5
|
||||
// 获取运算的结果
|
||||
String result = captcha.text();
|
||||
String uuid = codeKey + IdUtil.simpleUUID();
|
||||
String uuid = properties.getCodeKey() + IdUtil.simpleUUID();
|
||||
redisService.saveCode(uuid,result);
|
||||
return new ImgResult(captcha.toBase64(),uuid);
|
||||
// 验证码信息
|
||||
Map<String,Object> imgResult = new HashMap<String,Object>(2){{
|
||||
put("img", captcha.toBase64());
|
||||
put("uuid", uuid);
|
||||
}};
|
||||
return ResponseEntity.ok(imgResult);
|
||||
}
|
||||
|
||||
@ApiOperation("退出登录")
|
||||
@AnonymousAccess
|
||||
@DeleteMapping(value = "/logout")
|
||||
public ResponseEntity logout(HttpServletRequest request){
|
||||
onlineUserService.logout(jwtTokenUtil.getToken(request));
|
||||
onlineUserService.logout(tokenProvider.getToken(request));
|
||||
return new ResponseEntity(HttpStatus.OK);
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package me.zhengjie.modules.security.security;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-23
|
||||
* 返回token
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class AuthInfo implements Serializable {
|
||||
|
||||
private final String token;
|
||||
|
||||
private final JwtUser user;
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package me.zhengjie.modules.security.security;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-6-5 17:29:57
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class ImgResult {
|
||||
|
||||
private String img;
|
||||
|
||||
private String uuid;
|
||||
}
|
|
@ -8,6 +8,9 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
*/
|
||||
@Component
|
||||
public class JwtAccessDeniedHandler implements AccessDeniedHandler {
|
||||
|
||||
|
|
|
@ -13,9 +13,7 @@ import java.io.Serializable;
|
|||
* @author Zheng Jie
|
||||
*/
|
||||
@Component
|
||||
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable {
|
||||
|
||||
private static final long serialVersionUID = -8970718410437077606L;
|
||||
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
|
||||
|
||||
@Override
|
||||
public void commence(HttpServletRequest request,
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
package me.zhengjie.modules.security.security;
|
||||
|
||||
import io.jsonwebtoken.ExpiredJwtException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhengjie.modules.security.utils.JwtTokenUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class JwtAuthorizationTokenFilter extends OncePerRequestFilter {
|
||||
|
||||
|
||||
@Value("${jwt.online}")
|
||||
private String onlineKey;
|
||||
|
||||
private final UserDetailsService userDetailsService;
|
||||
private final JwtTokenUtil jwtTokenUtil;
|
||||
private final RedisTemplate redisTemplate;
|
||||
|
||||
public JwtAuthorizationTokenFilter(@Qualifier("jwtUserDetailsServiceImpl") UserDetailsService userDetailsService, JwtTokenUtil jwtTokenUtil, RedisTemplate redisTemplate) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
this.jwtTokenUtil = jwtTokenUtil;
|
||||
this.redisTemplate = redisTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
|
||||
String authToken = jwtTokenUtil.getToken(request);
|
||||
OnlineUser onlineUser = null;
|
||||
try {
|
||||
onlineUser = (OnlineUser)redisTemplate.opsForValue().get(onlineKey + authToken);
|
||||
} catch (ExpiredJwtException e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
if (onlineUser != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
||||
// It is not compelling necessary to load the use details from the database. You could also store the information
|
||||
// in the token and read it from it. It's up to you ;)
|
||||
JwtUser userDetails = (JwtUser)this.userDetailsService.loadUserByUsername(onlineUser.getUserName());
|
||||
// For simple validation it is completely sufficient to just check the token integrity. You don't have to call
|
||||
// the database compellingly. Again it's up to you ;)
|
||||
if (jwtTokenUtil.validateToken(authToken, userDetails)) {
|
||||
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
|
||||
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
}
|
||||
}
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package me.zhengjie.modules.security.security;
|
||||
|
||||
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
|
||||
/**
|
||||
* @author /
|
||||
*/
|
||||
public class TokenConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
|
||||
|
||||
private final TokenProvider tokenProvider;
|
||||
|
||||
public TokenConfigurer(TokenProvider tokenProvider){
|
||||
this.tokenProvider = tokenProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(HttpSecurity http) {
|
||||
TokenFilter customFilter = new TokenFilter(tokenProvider);
|
||||
http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package me.zhengjie.modules.security.security;
|
||||
|
||||
import io.jsonwebtoken.ExpiredJwtException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhengjie.modules.security.config.SecurityProperties;
|
||||
import me.zhengjie.modules.security.security.vo.OnlineUser;
|
||||
import me.zhengjie.modules.security.service.OnlineUserService;
|
||||
import me.zhengjie.utils.SpringContextHolder;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.filter.GenericFilterBean;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author /
|
||||
*/
|
||||
@Slf4j
|
||||
public class TokenFilter extends GenericFilterBean {
|
||||
|
||||
private final TokenProvider tokenProvider;
|
||||
|
||||
TokenFilter(TokenProvider tokenProvider) {
|
||||
this.tokenProvider = tokenProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
|
||||
throws IOException, ServletException {
|
||||
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
|
||||
String token = resolveToken(httpServletRequest);
|
||||
String requestRri = httpServletRequest.getRequestURI();
|
||||
// 验证 token 是否存在
|
||||
OnlineUser onlineUser = null;
|
||||
try {
|
||||
SecurityProperties properties = SpringContextHolder.getBean(SecurityProperties.class);
|
||||
OnlineUserService onlineUserService = SpringContextHolder.getBean(OnlineUserService.class);
|
||||
onlineUser = onlineUserService.getOne(properties.getOnlineKey() + token);
|
||||
} catch (ExpiredJwtException e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
if (onlineUser != null && StringUtils.hasText(token) && tokenProvider.validateToken(token)) {
|
||||
Authentication authentication = tokenProvider.getAuthentication(token);
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
log.debug("set Authentication to security context for '{}', uri: {}", authentication.getName(), requestRri);
|
||||
} else {
|
||||
log.debug("no valid JWT token found, uri: {}", requestRri);
|
||||
}
|
||||
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
}
|
||||
|
||||
private String resolveToken(HttpServletRequest request) {
|
||||
SecurityProperties properties = SpringContextHolder.getBean(SecurityProperties.class);
|
||||
String bearerToken = request.getHeader(properties.getHeader());
|
||||
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(properties.getTokenStartWith())) {
|
||||
return bearerToken.substring(7);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
package me.zhengjie.modules.security.security;
|
||||
|
||||
import io.jsonwebtoken.*;
|
||||
import io.jsonwebtoken.io.Decoders;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhengjie.modules.security.config.SecurityProperties;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.stereotype.Component;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.security.Key;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author /
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class TokenProvider implements InitializingBean {
|
||||
|
||||
private final SecurityProperties properties;
|
||||
private static final String AUTHORITIES_KEY = "auth";
|
||||
private Key key;
|
||||
|
||||
public TokenProvider(SecurityProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
byte[] keyBytes = Decoders.BASE64.decode(properties.getBase64Secret());
|
||||
this.key = Keys.hmacShaKeyFor(keyBytes);
|
||||
}
|
||||
|
||||
public String createToken(Authentication authentication, boolean rememberMe) {
|
||||
String authorities = authentication.getAuthorities().stream()
|
||||
.map(GrantedAuthority::getAuthority)
|
||||
.collect(Collectors.joining(","));
|
||||
|
||||
long now = (new Date()).getTime();
|
||||
Date validity;
|
||||
if (rememberMe) {
|
||||
validity = new Date(now + properties.getTokenValidityInSecondsForRememberMe());
|
||||
} else {
|
||||
validity = new Date(now + properties.getTokenValidityInSeconds());
|
||||
}
|
||||
|
||||
return Jwts.builder()
|
||||
.setSubject(authentication.getName())
|
||||
.claim(AUTHORITIES_KEY, authorities)
|
||||
.signWith(key, SignatureAlgorithm.HS512)
|
||||
.setExpiration(validity)
|
||||
.compact();
|
||||
}
|
||||
|
||||
Authentication getAuthentication(String token) {
|
||||
Claims claims = Jwts.parser()
|
||||
.setSigningKey(key)
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
|
||||
Collection<? extends GrantedAuthority> authorities =
|
||||
Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(","))
|
||||
.map(SimpleGrantedAuthority::new)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
User principal = new User(claims.getSubject(), "", authorities);
|
||||
|
||||
return new UsernamePasswordAuthenticationToken(principal, token, authorities);
|
||||
}
|
||||
|
||||
boolean validateToken(String authToken) {
|
||||
try {
|
||||
Jwts.parser().setSigningKey(key).parseClaimsJws(authToken);
|
||||
return true;
|
||||
} catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) {
|
||||
log.info("Invalid JWT signature.");
|
||||
e.printStackTrace();
|
||||
} catch (ExpiredJwtException e) {
|
||||
log.info("Expired JWT token.");
|
||||
e.printStackTrace();
|
||||
} catch (UnsupportedJwtException e) {
|
||||
log.info("Unsupported JWT token.");
|
||||
e.printStackTrace();
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.info("JWT token compact of handler are invalid.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getToken(HttpServletRequest request){
|
||||
final String requestHeader = request.getHeader(properties.getHeader());
|
||||
if (requestHeader != null && requestHeader.startsWith(properties.getTokenStartWith())) {
|
||||
return requestHeader.substring(7);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package me.zhengjie.modules.security.security;
|
||||
package me.zhengjie.modules.security.security.vo;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
@ -19,6 +19,8 @@ public class AuthUser {
|
|||
@NotBlank
|
||||
private String password;
|
||||
|
||||
private Boolean rememberMe;
|
||||
|
||||
private String code;
|
||||
|
||||
private String uuid = "";
|
|
@ -1,4 +1,4 @@
|
|||
package me.zhengjie.modules.security.security;
|
||||
package me.zhengjie.modules.security.security.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.AllArgsConstructor;
|
|
@ -1,4 +1,4 @@
|
|||
package me.zhengjie.modules.security.security;
|
||||
package me.zhengjie.modules.security.security.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
|
@ -1,50 +0,0 @@
|
|||
package me.zhengjie.modules.security.service;
|
||||
|
||||
import me.zhengjie.modules.system.domain.Menu;
|
||||
import me.zhengjie.modules.system.domain.Role;
|
||||
import me.zhengjie.modules.system.repository.RoleRepository;
|
||||
import me.zhengjie.modules.system.service.dto.UserDto;
|
||||
import me.zhengjie.utils.StringUtils;
|
||||
import org.springframework.cache.annotation.CacheConfig;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
*/
|
||||
@Service
|
||||
@CacheConfig(cacheNames = "role")
|
||||
public class JwtPermissionServiceImpl {
|
||||
|
||||
private final RoleRepository roleRepository;
|
||||
|
||||
public JwtPermissionServiceImpl(RoleRepository roleRepository) {
|
||||
this.roleRepository = roleRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* key的名称如有修改,请同步修改 UserServiceImpl 中的 update 方法
|
||||
* @param user 用户信息
|
||||
* @return Collection
|
||||
*/
|
||||
@Cacheable(key = "'loadPermissionByUser:' + #p0.username")
|
||||
public Collection<GrantedAuthority> mapToGrantedAuthorities(UserDto user) {
|
||||
|
||||
System.out.println("--------------------loadPermissionByUser:" + user.getUsername() + "---------------------");
|
||||
|
||||
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(permission -> new SimpleGrantedAuthority(permission))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
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()
|
|
@ -1,134 +0,0 @@
|
|||
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());
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
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:
|
||||
|
|
Loading…
Reference in New Issue