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