Commit fd9fb2a6 authored by dqjdda's avatar dqjdda
Browse files

Merge branch '2.3dev'

parents 7895e547 1839ef8d
...@@ -3,76 +3,47 @@ package me.zhengjie.modules.quartz.service; ...@@ -3,76 +3,47 @@ package me.zhengjie.modules.quartz.service;
import me.zhengjie.modules.quartz.domain.QuartzJob; import me.zhengjie.modules.quartz.domain.QuartzJob;
import me.zhengjie.modules.quartz.domain.QuartzLog; import me.zhengjie.modules.quartz.domain.QuartzLog;
import me.zhengjie.modules.quartz.service.dto.JobQueryCriteria; import me.zhengjie.modules.quartz.service.dto.JobQueryCriteria;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/** /**
* @author Zheng Jie * @author Zheng Jie
* @date 2019-01-07 * @date 2019-01-07
*/ */
@CacheConfig(cacheNames = "quartzJob")
public interface QuartzJobService { public interface QuartzJobService {
/**
* queryAll quartzJob
* @param criteria
* @param pageable
* @return
*/
@Cacheable
Object queryAll(JobQueryCriteria criteria, Pageable pageable); Object queryAll(JobQueryCriteria criteria, Pageable pageable);
/** List<QuartzJob> queryAll(JobQueryCriteria criteria);
* queryAll quartzLog
* @param criteria
* @param pageable
* @return
*/
Object queryAllLog(JobQueryCriteria criteria, Pageable pageable); Object queryAllLog(JobQueryCriteria criteria, Pageable pageable);
/** List<QuartzLog> queryAllLog(JobQueryCriteria criteria);
* create
* @param resources
* @return
*/
@CacheEvict(allEntries = true)
QuartzJob create(QuartzJob resources); QuartzJob create(QuartzJob resources);
/**
* update
* @param resources
* @return
*/
@CacheEvict(allEntries = true)
void update(QuartzJob resources); void update(QuartzJob resources);
/**
* del
* @param quartzJob
*/
@CacheEvict(allEntries = true)
void delete(QuartzJob quartzJob); void delete(QuartzJob quartzJob);
/**
* findById
* @param id
* @return
*/
@Cacheable(key = "#p0")
QuartzJob findById(Long id); QuartzJob findById(Long id);
/** /**
* 更改定时任务状态 * 更改定时任务状态
* @param quartzJob * @param quartzJob /
*/ */
@CacheEvict(allEntries = true)
void updateIsPause(QuartzJob quartzJob); void updateIsPause(QuartzJob quartzJob);
/** /**
* 立即执行定时任务 * 立即执行定时任务
* @param quartzJob * @param quartzJob /
*/ */
void execution(QuartzJob quartzJob); void execution(QuartzJob quartzJob);
void download(List<QuartzJob> queryAll, HttpServletResponse response) throws IOException;
void downloadLog(List<QuartzLog> queryAllLog, HttpServletResponse response) throws IOException;
} }
...@@ -3,6 +3,8 @@ package me.zhengjie.modules.quartz.service.dto; ...@@ -3,6 +3,8 @@ package me.zhengjie.modules.quartz.service.dto;
import lombok.Data; import lombok.Data;
import me.zhengjie.annotation.Query; import me.zhengjie.annotation.Query;
import java.sql.Timestamp;
/** /**
* @author Zheng Jie * @author Zheng Jie
* @date 2019-6-4 10:33:02 * @date 2019-6-4 10:33:02
...@@ -15,4 +17,10 @@ public class JobQueryCriteria { ...@@ -15,4 +17,10 @@ public class JobQueryCriteria {
@Query @Query
private Boolean isSuccess; private Boolean isSuccess;
@Query(type = Query.Type.GREATER_THAN,propName = "createTime")
private Timestamp startTime;
@Query(type = Query.Type.LESS_THAN,propName = "createTime")
private Timestamp endTime;
} }
...@@ -2,40 +2,55 @@ package me.zhengjie.modules.quartz.service.impl; ...@@ -2,40 +2,55 @@ package me.zhengjie.modules.quartz.service.impl;
import me.zhengjie.exception.BadRequestException; import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.quartz.domain.QuartzJob; import me.zhengjie.modules.quartz.domain.QuartzJob;
import me.zhengjie.modules.quartz.domain.QuartzLog;
import me.zhengjie.modules.quartz.repository.QuartzJobRepository; import me.zhengjie.modules.quartz.repository.QuartzJobRepository;
import me.zhengjie.modules.quartz.repository.QuartzLogRepository; import me.zhengjie.modules.quartz.repository.QuartzLogRepository;
import me.zhengjie.modules.quartz.service.QuartzJobService; import me.zhengjie.modules.quartz.service.QuartzJobService;
import me.zhengjie.modules.quartz.service.dto.JobQueryCriteria; import me.zhengjie.modules.quartz.service.dto.JobQueryCriteria;
import me.zhengjie.modules.quartz.utils.QuartzManage; import me.zhengjie.modules.quartz.utils.QuartzManage;
import me.zhengjie.utils.FileUtil;
import me.zhengjie.utils.PageUtil; import me.zhengjie.utils.PageUtil;
import me.zhengjie.utils.QueryHelp; import me.zhengjie.utils.QueryHelp;
import me.zhengjie.utils.ValidationUtil; import me.zhengjie.utils.ValidationUtil;
import org.quartz.CronExpression; import org.quartz.CronExpression;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/** /**
* @author Zheng Jie * @author Zheng Jie
* @date 2019-01-07 * @date 2019-01-07
*/ */
@Service(value = "quartzJobService") @Service(value = "quartzJobService")
@CacheConfig(cacheNames = "quartzJob")
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class) @Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class QuartzJobServiceImpl implements QuartzJobService { public class QuartzJobServiceImpl implements QuartzJobService {
@Autowired private final QuartzJobRepository quartzJobRepository;
private QuartzJobRepository quartzJobRepository;
private final QuartzLogRepository quartzLogRepository;
@Autowired private final QuartzManage quartzManage;
private QuartzLogRepository quartzLogRepository;
@Autowired public QuartzJobServiceImpl(QuartzJobRepository quartzJobRepository, QuartzLogRepository quartzLogRepository, QuartzManage quartzManage) {
private QuartzManage quartzManage; this.quartzJobRepository = quartzJobRepository;
this.quartzLogRepository = quartzLogRepository;
this.quartzManage = quartzManage;
}
@Override @Override
@Cacheable
public Object queryAll(JobQueryCriteria criteria, Pageable pageable){ public Object queryAll(JobQueryCriteria criteria, Pageable pageable){
return PageUtil.toPage(quartzJobRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable)); return PageUtil.toPage(quartzJobRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable));
} }
...@@ -46,13 +61,25 @@ public class QuartzJobServiceImpl implements QuartzJobService { ...@@ -46,13 +61,25 @@ public class QuartzJobServiceImpl implements QuartzJobService {
} }
@Override @Override
public List<QuartzJob> queryAll(JobQueryCriteria criteria) {
return quartzJobRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder));
}
@Override
public List<QuartzLog> queryAllLog(JobQueryCriteria criteria) {
return quartzLogRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder));
}
@Override
@Cacheable(key = "#p0")
public QuartzJob findById(Long id) { public QuartzJob findById(Long id) {
Optional<QuartzJob> quartzJob = quartzJobRepository.findById(id); QuartzJob quartzJob = quartzJobRepository.findById(id).orElseGet(QuartzJob::new);
ValidationUtil.isNull(quartzJob,"QuartzJob","id",id); ValidationUtil.isNull(quartzJob.getId(),"QuartzJob","id",id);
return quartzJob.get(); return quartzJob;
} }
@Override @Override
@CacheEvict(allEntries = true)
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public QuartzJob create(QuartzJob resources) { public QuartzJob create(QuartzJob resources) {
if (!CronExpression.isValidExpression(resources.getCronExpression())){ if (!CronExpression.isValidExpression(resources.getCronExpression())){
...@@ -64,6 +91,7 @@ public class QuartzJobServiceImpl implements QuartzJobService { ...@@ -64,6 +91,7 @@ public class QuartzJobServiceImpl implements QuartzJobService {
} }
@Override @Override
@CacheEvict(allEntries = true)
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void update(QuartzJob resources) { public void update(QuartzJob resources) {
if(resources.getId().equals(1L)){ if(resources.getId().equals(1L)){
...@@ -77,6 +105,7 @@ public class QuartzJobServiceImpl implements QuartzJobService { ...@@ -77,6 +105,7 @@ public class QuartzJobServiceImpl implements QuartzJobService {
} }
@Override @Override
@CacheEvict(allEntries = true)
public void updateIsPause(QuartzJob quartzJob) { public void updateIsPause(QuartzJob quartzJob) {
if(quartzJob.getId().equals(1L)){ if(quartzJob.getId().equals(1L)){
throw new BadRequestException("该任务不可操作"); throw new BadRequestException("该任务不可操作");
...@@ -100,6 +129,7 @@ public class QuartzJobServiceImpl implements QuartzJobService { ...@@ -100,6 +129,7 @@ public class QuartzJobServiceImpl implements QuartzJobService {
} }
@Override @Override
@CacheEvict(allEntries = true)
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void delete(QuartzJob quartzJob) { public void delete(QuartzJob quartzJob) {
if(quartzJob.getId().equals(1L)){ if(quartzJob.getId().equals(1L)){
...@@ -108,4 +138,41 @@ public class QuartzJobServiceImpl implements QuartzJobService { ...@@ -108,4 +138,41 @@ public class QuartzJobServiceImpl implements QuartzJobService {
quartzManage.deleteJob(quartzJob); quartzManage.deleteJob(quartzJob);
quartzJobRepository.delete(quartzJob); quartzJobRepository.delete(quartzJob);
} }
@Override
public void download(List<QuartzJob> quartzJobs, HttpServletResponse response) throws IOException {
List<Map<String, Object>> list = new ArrayList<>();
for (QuartzJob quartzJob : quartzJobs) {
Map<String,Object> map = new LinkedHashMap<>();
map.put("任务名称", quartzJob.getJobName());
map.put("Bean名称", quartzJob.getBeanName());
map.put("执行方法", quartzJob.getMethodName());
map.put("参数", quartzJob.getParams());
map.put("表达式", quartzJob.getCronExpression());
map.put("状态", quartzJob.getIsPause() ? "暂停中" : "运行中");
map.put("描述", quartzJob.getRemark());
map.put("创建日期", quartzJob.getCreateTime());
list.add(map);
}
FileUtil.downloadExcel(list, response);
}
@Override
public void downloadLog(List<QuartzLog> queryAllLog, HttpServletResponse response) throws IOException {
List<Map<String, Object>> list = new ArrayList<>();
for (QuartzLog quartzLog : queryAllLog) {
Map<String,Object> map = new LinkedHashMap<>();
map.put("任务名称", quartzLog.getJobName());
map.put("Bean名称", quartzLog.getBeanName());
map.put("执行方法", quartzLog.getMethodName());
map.put("参数", quartzLog.getParams());
map.put("表达式", quartzLog.getCronExpression());
map.put("异常详情", quartzLog.getExceptionDetail());
map.put("耗时/毫秒", quartzLog.getTime());
map.put("状态", quartzLog.getIsSuccess() ? "成功" : "失败");
map.put("创建日期", quartzLog.getCreateTime());
list.add(map);
}
FileUtil.downloadExcel(list, response);
}
} }
package me.zhengjie.modules.quartz.task; package me.zhengjie.modules.quartz.task;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import me.zhengjie.exception.BadRequestException;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**
......
package me.zhengjie.modules.quartz.task; package me.zhengjie.modules.quartz.task;
import me.zhengjie.modules.monitor.service.VisitsService; import me.zhengjie.modules.monitor.service.VisitsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**
...@@ -11,8 +10,11 @@ import org.springframework.stereotype.Component; ...@@ -11,8 +10,11 @@ import org.springframework.stereotype.Component;
@Component @Component
public class VisitsTask { public class VisitsTask {
@Autowired private final VisitsService visitsService;
private VisitsService visitsService;
public VisitsTask(VisitsService visitsService) {
this.visitsService = visitsService;
}
public void run(){ public void run(){
visitsService.save(); visitsService.save();
......
package me.zhengjie.modules.quartz.utils; package me.zhengjie.modules.quartz.utils;
import me.zhengjie.config.thread.TheadFactoryName;
import me.zhengjie.config.thread.ThreadPoolExecutorUtil;
import me.zhengjie.modules.quartz.domain.QuartzJob; import me.zhengjie.modules.quartz.domain.QuartzJob;
import me.zhengjie.modules.quartz.domain.QuartzLog; import me.zhengjie.modules.quartz.domain.QuartzLog;
import me.zhengjie.modules.quartz.repository.QuartzLogRepository; import me.zhengjie.modules.quartz.repository.QuartzLogRepository;
...@@ -11,13 +13,11 @@ import org.slf4j.Logger; ...@@ -11,13 +13,11 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.quartz.QuartzJobBean; import org.springframework.scheduling.quartz.QuartzJobBean;
import java.util.concurrent.ExecutorService; import java.util.concurrent.*;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/** /**
* 参考人人开源,https://gitee.com/renrenio/renren-security * 参考人人开源,https://gitee.com/renrenio/renren-security
* @author * @author /
* @date 2019-01-07 * @date 2019-01-07
*/ */
@Async @Async
...@@ -25,16 +25,16 @@ public class ExecutionJob extends QuartzJobBean { ...@@ -25,16 +25,16 @@ public class ExecutionJob extends QuartzJobBean {
private Logger logger = LoggerFactory.getLogger(this.getClass()); private Logger logger = LoggerFactory.getLogger(this.getClass());
// 建议自定义线程池实现方式,该处仅供参考 // 该处仅供参考
private ExecutorService executorService = Executors.newSingleThreadExecutor(); private final static ThreadPoolExecutor executor = ThreadPoolExecutorUtil.getPoll();
@Override @Override
@SuppressWarnings("unchecked")
protected void executeInternal(JobExecutionContext context) { protected void executeInternal(JobExecutionContext context) {
QuartzJob quartzJob = (QuartzJob) context.getMergedJobDataMap().get(QuartzJob.JOB_KEY); QuartzJob quartzJob = (QuartzJob) context.getMergedJobDataMap().get(QuartzJob.JOB_KEY);
// 获取spring bean // 获取spring bean
QuartzLogRepository quartzLogRepository = SpringContextHolder.getBean("quartzLogRepository"); QuartzLogRepository quartzLogRepository = SpringContextHolder.getBean(QuartzLogRepository.class);
QuartzJobService quartzJobService = SpringContextHolder.getBean("quartzJobService"); QuartzJobService quartzJobService = SpringContextHolder.getBean(QuartzJobService.class);
QuartzManage quartzManage = SpringContextHolder.getBean("quartzManage");
QuartzLog log = new QuartzLog(); QuartzLog log = new QuartzLog();
log.setJobName(quartzJob.getJobName()); log.setJobName(quartzJob.getJobName());
...@@ -48,7 +48,7 @@ public class ExecutionJob extends QuartzJobBean { ...@@ -48,7 +48,7 @@ public class ExecutionJob extends QuartzJobBean {
logger.info("任务准备执行,任务名称:{}", quartzJob.getJobName()); logger.info("任务准备执行,任务名称:{}", quartzJob.getJobName());
QuartzRunnable task = new QuartzRunnable(quartzJob.getBeanName(), quartzJob.getMethodName(), QuartzRunnable task = new QuartzRunnable(quartzJob.getBeanName(), quartzJob.getMethodName(),
quartzJob.getParams()); quartzJob.getParams());
Future<?> future = executorService.submit(task); Future<?> future = executor.submit(task);
future.get(); future.get();
long times = System.currentTimeMillis() - startTime; long times = System.currentTimeMillis() - startTime;
log.setTime(times); log.setTime(times);
......
...@@ -56,8 +56,7 @@ public class QuartzManage { ...@@ -56,8 +56,7 @@ public class QuartzManage {
/** /**
* 更新job cron表达式 * 更新job cron表达式
* @param quartzJob * @param quartzJob /
* @throws SchedulerException
*/ */
public void updateJobCron(QuartzJob quartzJob){ public void updateJobCron(QuartzJob quartzJob){
try { try {
...@@ -88,8 +87,7 @@ public class QuartzManage { ...@@ -88,8 +87,7 @@ public class QuartzManage {
/** /**
* 删除一个job * 删除一个job
* @param quartzJob * @param quartzJob /
* @throws SchedulerException
*/ */
public void deleteJob(QuartzJob quartzJob){ public void deleteJob(QuartzJob quartzJob){
try { try {
...@@ -104,8 +102,7 @@ public class QuartzManage { ...@@ -104,8 +102,7 @@ public class QuartzManage {
/** /**
* 恢复一个job * 恢复一个job
* @param quartzJob * @param quartzJob /
* @throws SchedulerException
*/ */
public void resumeJob(QuartzJob quartzJob){ public void resumeJob(QuartzJob quartzJob){
try { try {
...@@ -124,8 +121,7 @@ public class QuartzManage { ...@@ -124,8 +121,7 @@ public class QuartzManage {
/** /**
* 立即执行job * 立即执行job
* @param quartzJob * @param quartzJob /
* @throws SchedulerException
*/ */
public void runAJobNow(QuartzJob quartzJob){ public void runAJobNow(QuartzJob quartzJob){
try { try {
...@@ -146,8 +142,7 @@ public class QuartzManage { ...@@ -146,8 +142,7 @@ public class QuartzManage {
/** /**
* 暂停一个job * 暂停一个job
* @param quartzJob * @param quartzJob /
* @throws SchedulerException
*/ */
public void pauseJob(QuartzJob quartzJob){ public void pauseJob(QuartzJob quartzJob){
try { try {
......
package me.zhengjie.modules.quartz.utils; package me.zhengjie.modules.quartz.utils;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.utils.SpringContextHolder; import me.zhengjie.utils.SpringContextHolder;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
...@@ -10,7 +9,7 @@ import java.util.concurrent.Callable; ...@@ -10,7 +9,7 @@ import java.util.concurrent.Callable;
/** /**
* 执行定时任务 * 执行定时任务
* @author * @author /
*/ */
@Slf4j @Slf4j
public class QuartzRunnable implements Callable { public class QuartzRunnable implements Callable {
......
package me.zhengjie.modules.security.config; package me.zhengjie.modules.security.config;
import me.zhengjie.annotation.AnonymousAccess;
import me.zhengjie.config.ElPermissionConfig;
import me.zhengjie.modules.security.security.JwtAuthenticationEntryPoint; import me.zhengjie.modules.security.security.JwtAuthenticationEntryPoint;
import me.zhengjie.modules.security.security.JwtAuthorizationTokenFilter; import me.zhengjie.modules.security.security.JwtAuthorizationTokenFilter;
import me.zhengjie.modules.security.service.JwtUserDetailsService; import me.zhengjie.modules.security.service.JwtUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
...@@ -19,29 +23,37 @@ import org.springframework.security.config.http.SessionCreationPolicy; ...@@ -19,29 +23,37 @@ import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@Configuration @Configuration
@EnableWebSecurity @EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) @EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter { public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired private final JwtAuthenticationEntryPoint unauthorizedHandler;
private JwtAuthenticationEntryPoint unauthorizedHandler;
@Autowired private final JwtUserDetailsService jwtUserDetailsService;
private JwtUserDetailsService jwtUserDetailsService;
/** private final ApplicationContext applicationContext;
* 自定义基于JWT的安全过滤器
*/ // 自定义基于JWT的安全过滤器
@Autowired private final JwtAuthorizationTokenFilter authenticationTokenFilter;
JwtAuthorizationTokenFilter authenticationTokenFilter;
@Value("${jwt.header}") @Value("${jwt.header}")
private String tokenHeader; private String tokenHeader;
@Value("${jwt.auth.path}") public SecurityConfig(JwtAuthenticationEntryPoint unauthorizedHandler, JwtUserDetailsService jwtUserDetailsService, JwtAuthorizationTokenFilter authenticationTokenFilter, ApplicationContext applicationContext) {
private String loginPath; this.unauthorizedHandler = unauthorizedHandler;
this.jwtUserDetailsService = jwtUserDetailsService;
this.authenticationTokenFilter = authenticationTokenFilter;
this.applicationContext = applicationContext;
}
@Autowired @Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
...@@ -69,18 +81,26 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { ...@@ -69,18 +81,26 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override @Override
protected void configure(HttpSecurity httpSecurity) throws Exception { protected void configure(HttpSecurity httpSecurity) throws Exception {
// 搜寻 匿名标记 url: PreAuthorize("hasAnyRole('anonymous')") 和 PreAuthorize("@el.check('anonymous')") 和 AnonymousAccess
Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = applicationContext.getBean(RequestMappingHandlerMapping.class).getHandlerMethods();
Set<String> anonymousUrls = new HashSet<>();
for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethodMap.entrySet()) {
HandlerMethod handlerMethod = infoEntry.getValue();
AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class);
PreAuthorize preAuthorize = handlerMethod.getMethodAnnotation(PreAuthorize.class);
if (null != preAuthorize && preAuthorize.value().contains("anonymous")) {
anonymousUrls.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
} else if (null != anonymousAccess && null == preAuthorize) {
anonymousUrls.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
}
}
httpSecurity httpSecurity
// 禁用 CSRF // 禁用 CSRF
.csrf().disable() .csrf().disable()
// 授权异常 // 授权异常
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and() .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
// 不创建会话 // 不创建会话
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
// 过滤请求 // 过滤请求
.authorizeRequests() .authorizeRequests()
.antMatchers( .antMatchers(
...@@ -90,35 +110,24 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { ...@@ -90,35 +110,24 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
"/**/*.css", "/**/*.css",
"/**/*.js" "/**/*.js"
).anonymous() ).anonymous()
.antMatchers( HttpMethod.POST,"/auth/"+loginPath).anonymous()
.antMatchers("/auth/vCode").anonymous()
// 支付宝回调
.antMatchers("/api/aliPay/return").anonymous()
.antMatchers("/api/aliPay/notify").anonymous()
// swagger start // swagger start
.antMatchers("/swagger-ui.html").anonymous() .antMatchers("/swagger-ui.html").permitAll()
.antMatchers("/swagger-resources/**").anonymous() .antMatchers("/swagger-resources/**").permitAll()
.antMatchers("/webjars/**").anonymous() .antMatchers("/webjars/**").permitAll()
.antMatchers("/*/api-docs").anonymous() .antMatchers("/*/api-docs").permitAll()
// swagger end // swagger end
// 接口限流测试
.antMatchers("/test/**").anonymous()
// 文件 // 文件
.antMatchers("/avatar/**").anonymous() .antMatchers("/avatar/**").permitAll()
.antMatchers("/file/**").anonymous() .antMatchers("/file/**").permitAll()
// 放行OPTIONS请求 // 放行OPTIONS请求
.antMatchers(HttpMethod.OPTIONS, "/**").anonymous() .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers("/druid/**").permitAll()
.antMatchers("/druid/**").anonymous() // 自定义匿名访问所有url放行 : 允许 匿名和带权限以及登录用户访问
.antMatchers(anonymousUrls.toArray(new String[0])).permitAll()
// 所有请求都需要认证 // 所有请求都需要认证
.anyRequest().authenticated() .anyRequest().authenticated()
// 防止iframe 造成跨域 // 防止iframe 造成跨域
.and().headers().frameOptions().disable(); .and().headers().frameOptions().disable();
httpSecurity httpSecurity
.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); .addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
} }
......
package me.zhengjie.modules.security.rest; package me.zhengjie.modules.security.rest;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import com.wf.captcha.ArithmeticCaptcha;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import me.zhengjie.annotation.AnonymousAccess;
import me.zhengjie.aop.log.Log; import me.zhengjie.aop.log.Log;
import me.zhengjie.exception.BadRequestException; import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.monitor.service.RedisService; import me.zhengjie.modules.monitor.service.RedisService;
import me.zhengjie.modules.security.security.AuthenticationInfo; import me.zhengjie.modules.security.security.AuthInfo;
import me.zhengjie.modules.security.security.AuthorizationUser; import me.zhengjie.modules.security.security.AuthUser;
import me.zhengjie.modules.security.security.ImgResult; import me.zhengjie.modules.security.security.ImgResult;
import me.zhengjie.modules.security.security.JwtUser; import me.zhengjie.modules.security.security.JwtUser;
import me.zhengjie.modules.security.utils.VerifyCodeUtils; import me.zhengjie.modules.security.service.OnlineUserService;
import me.zhengjie.utils.EncryptUtils; import me.zhengjie.utils.EncryptUtils;
import me.zhengjie.modules.security.utils.JwtTokenUtil; import me.zhengjie.modules.security.utils.JwtTokenUtil;
import me.zhengjie.utils.SecurityUtils; import me.zhengjie.utils.SecurityUtils;
import me.zhengjie.utils.StringUtils; import me.zhengjie.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AccountExpiredException; import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/** /**
* @author Zheng Jie * @author Zheng Jie
...@@ -34,30 +35,33 @@ import java.io.IOException; ...@@ -34,30 +35,33 @@ import java.io.IOException;
*/ */
@Slf4j @Slf4j
@RestController @RestController
@RequestMapping("auth") @RequestMapping("/auth")
@Api(tags = "系统:系统授权接口")
public class AuthenticationController { public class AuthenticationController {
@Value("${jwt.header}") @Value("${jwt.codeKey}")
private String tokenHeader; private String codeKey;
@Autowired private final JwtTokenUtil jwtTokenUtil;
private JwtTokenUtil jwtTokenUtil;
@Autowired private final RedisService redisService;
private RedisService redisService;
@Autowired private final UserDetailsService userDetailsService;
@Qualifier("jwtUserDetailsService")
private UserDetailsService userDetailsService; private final OnlineUserService onlineUserService;
public AuthenticationController(JwtTokenUtil jwtTokenUtil, RedisService redisService, @Qualifier("jwtUserDetailsService") UserDetailsService userDetailsService, OnlineUserService onlineUserService) {
this.jwtTokenUtil = jwtTokenUtil;
this.redisService = redisService;
this.userDetailsService = userDetailsService;
this.onlineUserService = onlineUserService;
}
/**
* 登录授权
* @param authorizationUser
* @return
*/
@Log("用户登录") @Log("用户登录")
@PostMapping(value = "${jwt.auth.path}") @ApiOperation("登录授权")
public ResponseEntity login(@Validated @RequestBody AuthorizationUser authorizationUser){ @AnonymousAccess
@PostMapping(value = "/login")
public ResponseEntity login(@Validated @RequestBody AuthUser authorizationUser, HttpServletRequest request){
// 查询验证码 // 查询验证码
String code = redisService.getCodeVal(authorizationUser.getUuid()); String code = redisService.getCodeVal(authorizationUser.getUuid());
...@@ -78,45 +82,41 @@ public class AuthenticationController { ...@@ -78,45 +82,41 @@ public class AuthenticationController {
if(!jwtUser.isEnabled()){ if(!jwtUser.isEnabled()){
throw new AccountExpiredException("账号已停用,请联系管理员"); throw new AccountExpiredException("账号已停用,请联系管理员");
} }
// 生成令牌 // 生成令牌
final String token = jwtTokenUtil.generateToken(jwtUser); final String token = jwtTokenUtil.generateToken(jwtUser);
// 保存在线信息
onlineUserService.save(jwtUser, token, request);
// 返回 token // 返回 token
return ResponseEntity.ok(new AuthenticationInfo(token,jwtUser)); return ResponseEntity.ok(new AuthInfo(token,jwtUser));
} }
/** @ApiOperation("获取用户信息")
* 获取用户信息 @GetMapping(value = "/info")
* @return
*/
@GetMapping(value = "${jwt.auth.account}")
public ResponseEntity getUserInfo(){ public ResponseEntity getUserInfo(){
JwtUser jwtUser = (JwtUser)userDetailsService.loadUserByUsername(SecurityUtils.getUsername()); JwtUser jwtUser = (JwtUser)userDetailsService.loadUserByUsername(SecurityUtils.getUsername());
return ResponseEntity.ok(jwtUser); return ResponseEntity.ok(jwtUser);
} }
/** @ApiOperation("获取验证码")
* 获取验证码 @AnonymousAccess
*/ @GetMapping(value = "/code")
@GetMapping(value = "vCode") public ImgResult getCode(){
public ImgResult getCode(HttpServletResponse response) throws IOException { // 算术类型 https://gitee.com/whvse/EasyCaptcha
ArithmeticCaptcha captcha = new ArithmeticCaptcha(111, 36);
// 几位数运算,默认是两位
captcha.setLen(2);
// 获取运算的结果:5
String result = captcha.text();
String uuid = codeKey + IdUtil.simpleUUID();
redisService.saveCode(uuid,result);
return new ImgResult(captcha.toBase64(),uuid);
}
//生成随机字串 @ApiOperation("退出登录")
String verifyCode = VerifyCodeUtils.generateVerifyCode(4); @AnonymousAccess
String uuid = IdUtil.simpleUUID(); @DeleteMapping(value = "/logout")
redisService.saveCode(uuid,verifyCode); public ResponseEntity logout(HttpServletRequest request){
// 生成图片 onlineUserService.logout(jwtTokenUtil.getToken(request));
int w = 111, h = 36; return new ResponseEntity(HttpStatus.OK);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
VerifyCodeUtils.outputImage(w, h, stream, verifyCode);
try {
return new ImgResult(Base64.encode(stream.toByteArray()),uuid);
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
stream.close();
}
} }
} }
package me.zhengjie.modules.security.rest;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import me.zhengjie.aop.log.Log;
import me.zhengjie.modules.security.service.OnlineUserService;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@RestController
@RequestMapping("/auth/online")
@Api(tags = "系统:在线用户管理")
public class OnlineController {
private final OnlineUserService onlineUserService;
public OnlineController(OnlineUserService onlineUserService) {
this.onlineUserService = onlineUserService;
}
@ApiOperation("查询在线用户")
@GetMapping
@PreAuthorize("@el.check()")
public ResponseEntity getAll(String filter, Pageable pageable){
return new ResponseEntity<>(onlineUserService.getAll(filter, pageable),HttpStatus.OK);
}
@Log("导出数据")
@ApiOperation("导出数据")
@GetMapping(value = "/download")
@PreAuthorize("@el.check()")
public void download(HttpServletResponse response, String filter) throws IOException {
onlineUserService.download(onlineUserService.getAll(filter), response);
}
@ApiOperation("踢出用户")
@DeleteMapping(value = "/{key}")
@PreAuthorize("@el.check()")
public ResponseEntity delete(@PathVariable String key) throws Exception {
onlineUserService.kickOut(key);
return new ResponseEntity(HttpStatus.OK);
}
}
package me.zhengjie.modules.security.security; package me.zhengjie.modules.security.security;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import java.io.Serializable; import java.io.Serializable;
/** /**
* @author Zheng Jie * @author Zheng Jie
* @date 2018-11-23 * @date 2018-11-23
* 返回token * 返回token
*/ */
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
public class AuthenticationInfo implements Serializable { public class AuthInfo implements Serializable {
private final String token; private final String token;
private final JwtUser user; private final JwtUser user;
} }
...@@ -11,7 +11,7 @@ import javax.validation.constraints.NotBlank; ...@@ -11,7 +11,7 @@ import javax.validation.constraints.NotBlank;
*/ */
@Getter @Getter
@Setter @Setter
public class AuthorizationUser { public class AuthUser {
@NotBlank @NotBlank
private String username; private String username;
......
...@@ -18,9 +18,7 @@ public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Se ...@@ -18,9 +18,7 @@ public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Se
public void commence(HttpServletRequest request, public void commence(HttpServletRequest request,
HttpServletResponse response, HttpServletResponse response,
AuthenticationException authException) throws IOException { AuthenticationException authException) throws IOException {
/** // 当用户尝试访问安全的REST资源而不提供任何凭据时,将调用此方法发送401 响应
* 当用户尝试访问安全的REST资源而不提供任何凭据时,将调用此方法发送401 响应
*/
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException==null?"Unauthorized":authException.getMessage()); response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException==null?"Unauthorized":authException.getMessage());
} }
} }
...@@ -3,11 +3,12 @@ package me.zhengjie.modules.security.security; ...@@ -3,11 +3,12 @@ package me.zhengjie.modules.security.security;
import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import me.zhengjie.modules.security.utils.JwtTokenUtil; 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.Qualifier;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
...@@ -22,38 +23,33 @@ import java.io.IOException; ...@@ -22,38 +23,33 @@ import java.io.IOException;
@Component @Component
public class JwtAuthorizationTokenFilter extends OncePerRequestFilter { public class JwtAuthorizationTokenFilter extends OncePerRequestFilter {
@Value("${jwt.online}")
private String onlineKey;
private final UserDetailsService userDetailsService; private final UserDetailsService userDetailsService;
private final JwtTokenUtil jwtTokenUtil; private final JwtTokenUtil jwtTokenUtil;
private final String tokenHeader; private final RedisTemplate redisTemplate;
public JwtAuthorizationTokenFilter(@Qualifier("jwtUserDetailsService") UserDetailsService userDetailsService, JwtTokenUtil jwtTokenUtil, @Value("${jwt.header}") String tokenHeader) { public JwtAuthorizationTokenFilter(@Qualifier("jwtUserDetailsService") UserDetailsService userDetailsService, JwtTokenUtil jwtTokenUtil, RedisTemplate redisTemplate) {
this.userDetailsService = userDetailsService; this.userDetailsService = userDetailsService;
this.jwtTokenUtil = jwtTokenUtil; this.jwtTokenUtil = jwtTokenUtil;
this.tokenHeader = tokenHeader; this.redisTemplate = redisTemplate;
} }
@Override @Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
String authToken = jwtTokenUtil.getToken(request);
final String requestHeader = request.getHeader(this.tokenHeader); OnlineUser onlineUser = null;
try {
String username = null; onlineUser = (OnlineUser)redisTemplate.opsForValue().get(onlineKey + authToken);
String authToken = null; } catch (ExpiredJwtException e) {
if (requestHeader != null && requestHeader.startsWith("Bearer ")) { log.error(e.getMessage());
authToken = requestHeader.substring(7);
try {
username = jwtTokenUtil.getUsernameFromToken(authToken);
} catch (ExpiredJwtException e) {
log.error(e.getMessage());
}
} }
if (onlineUser != null && SecurityContextHolder.getContext().getAuthentication() == null) {
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
// It is not compelling necessary to load the use details from the database. You could also store the information // 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 ;) // in the token and read it from it. It's up to you ;)
JwtUser userDetails = (JwtUser)this.userDetailsService.loadUserByUsername(username); 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 // 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 ;) // the database compellingly. Again it's up to you ;)
if (jwtTokenUtil.validateToken(authToken, userDetails)) { if (jwtTokenUtil.validateToken(authToken, userDetails)) {
......
package me.zhengjie.modules.security.security;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
/**
* @author Zheng Jie
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OnlineUser {
private String userName;
private String job;
private String browser;
private String ip;
private String address;
private String key;
private Date loginTime;
}
package me.zhengjie.modules.security.service; 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.domain.Role;
import me.zhengjie.modules.system.repository.RoleRepository; import me.zhengjie.modules.system.repository.RoleRepository;
import me.zhengjie.modules.system.service.dto.UserDTO; import me.zhengjie.modules.system.service.dto.UserDTO;
import org.springframework.beans.factory.annotation.Autowired; import me.zhengjie.utils.StringUtils;
import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
...@@ -17,13 +19,16 @@ import java.util.stream.Collectors; ...@@ -17,13 +19,16 @@ import java.util.stream.Collectors;
@CacheConfig(cacheNames = "role") @CacheConfig(cacheNames = "role")
public class JwtPermissionService { public class JwtPermissionService {
@Autowired private final RoleRepository roleRepository;
private RoleRepository roleRepository;
public JwtPermissionService(RoleRepository roleRepository) {
this.roleRepository = roleRepository;
}
/** /**
* key的名称如有修改,请同步修改 UserServiceImpl 中的 update 方法 * key的名称如有修改,请同步修改 UserServiceImpl 中的 update 方法
* @param user * @param user 用户信息
* @return * @return Collection
*/ */
@Cacheable(key = "'loadPermissionByUser:' + #p0.username") @Cacheable(key = "'loadPermissionByUser:' + #p0.username")
public Collection<GrantedAuthority> mapToGrantedAuthorities(UserDTO user) { public Collection<GrantedAuthority> mapToGrantedAuthorities(UserDTO user) {
...@@ -31,9 +36,13 @@ public class JwtPermissionService { ...@@ -31,9 +36,13 @@ public class JwtPermissionService {
System.out.println("--------------------loadPermissionByUser:" + user.getUsername() + "---------------------"); System.out.println("--------------------loadPermissionByUser:" + user.getUsername() + "---------------------");
Set<Role> roles = roleRepository.findByUsers_Id(user.getId()); 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());
return roles.stream().flatMap(role -> role.getPermissions().stream()) permissions.addAll(
.map(permission -> new SimpleGrantedAuthority(permission.getName())) 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()); .collect(Collectors.toList());
} }
} }
...@@ -4,7 +4,6 @@ import me.zhengjie.exception.BadRequestException; ...@@ -4,7 +4,6 @@ import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.security.security.JwtUser; import me.zhengjie.modules.security.security.JwtUser;
import me.zhengjie.modules.system.service.UserService; import me.zhengjie.modules.system.service.UserService;
import me.zhengjie.modules.system.service.dto.*; import me.zhengjie.modules.system.service.dto.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
...@@ -20,11 +19,14 @@ import java.util.Optional; ...@@ -20,11 +19,14 @@ import java.util.Optional;
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class) @Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class JwtUserDetailsService implements UserDetailsService { public class JwtUserDetailsService implements UserDetailsService {
@Autowired private final UserService userService;
private UserService userService;
@Autowired private final JwtPermissionService permissionService;
private JwtPermissionService permissionService;
public JwtUserDetailsService(UserService userService, JwtPermissionService permissionService) {
this.userService = userService;
this.permissionService = permissionService;
}
@Override @Override
public UserDetails loadUserByUsername(String username){ public UserDetails loadUserByUsername(String username){
......
package me.zhengjie.modules.security.service;
import me.zhengjie.modules.security.security.JwtUser;
import me.zhengjie.modules.security.security.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;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* @author Zheng Jie
* @Date 2019年10月26日21:56:27
*/
@Service
@SuppressWarnings({"unchecked","all"})
public class OnlineUserService {
@Value("${jwt.expiration}")
private Long expiration;
@Value("${jwt.online}")
private String onlineKey;
private final RedisTemplate redisTemplate;
public OnlineUserService(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
public void save(JwtUser jwtUser, String token, HttpServletRequest request){
String job = jwtUser.getDept() + "/" + jwtUser.getJob();
String ip = StringUtils.getIp(request);
String browser = StringUtils.getBrowser(request);
String address = StringUtils.getCityInfo(ip);
OnlineUser onlineUser = null;
try {
onlineUser = new OnlineUser(jwtUser.getUsername(), job, browser , ip, address, EncryptUtils.desEncrypt(token), new Date());
} catch (Exception e) {
e.printStackTrace();
}
redisTemplate.opsForValue().set(onlineKey + token, onlineUser);
redisTemplate.expire(onlineKey + token,expiration, TimeUnit.MILLISECONDS);
}
public Page<OnlineUser> getAll(String filter, Pageable pageable){
List<OnlineUser> onlineUsers = getAll(filter);
return new PageImpl<OnlineUser>(
PageUtil.toPage(pageable.getPageNumber(),pageable.getPageSize(),onlineUsers),
pageable,
onlineUsers.size());
}
public List<OnlineUser> getAll(String filter){
List<String> keys = new ArrayList<>(redisTemplate.keys(onlineKey + "*"));
Collections.reverse(keys);
List<OnlineUser> onlineUsers = new ArrayList<>();
for (String key : keys) {
OnlineUser onlineUser = (OnlineUser) redisTemplate.opsForValue().get(key);
if(StringUtils.isNotBlank(filter)){
if(onlineUser.toString().contains(filter)){
onlineUsers.add(onlineUser);
}
} else {
onlineUsers.add(onlineUser);
}
}
Collections.sort(onlineUsers, (o1, o2) -> {
return o2.getLoginTime().compareTo(o1.getLoginTime());
});
return onlineUsers;
}
public void kickOut(String val) throws Exception {
String key = onlineKey + EncryptUtils.desDecrypt(val);
redisTemplate.delete(key);
}
public void logout(String token) {
String key = onlineKey + token;
redisTemplate.delete(key);
}
public void download(List<OnlineUser> all, HttpServletResponse response) throws IOException {
List<Map<String, Object>> list = new ArrayList<>();
for (OnlineUser user : all) {
Map<String,Object> map = new LinkedHashMap<>();
map.put("用户名", user.getUserName());
map.put("岗位", user.getJob());
map.put("登录IP", user.getIp());
map.put("登录地点", user.getAddress());
map.put("浏览器", user.getBrowser());
map.put("登录日期", user.getLoginTime());
list.add(map);
}
FileUtil.downloadExcel(list, response);
}
}
...@@ -6,6 +6,8 @@ import me.zhengjie.modules.security.security.JwtUser; ...@@ -6,6 +6,8 @@ import me.zhengjie.modules.security.security.JwtUser;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
...@@ -31,15 +33,15 @@ public class JwtTokenUtil implements Serializable { ...@@ -31,15 +33,15 @@ public class JwtTokenUtil implements Serializable {
return getClaimFromToken(token, Claims::getSubject); return getClaimFromToken(token, Claims::getSubject);
} }
public Date getIssuedAtDateFromToken(String token) { private Date getIssuedAtDateFromToken(String token) {
return getClaimFromToken(token, Claims::getIssuedAt); return getClaimFromToken(token, Claims::getIssuedAt);
} }
public Date getExpirationDateFromToken(String token) { private Date getExpirationDateFromToken(String token) {
return getClaimFromToken(token, Claims::getExpiration); return getClaimFromToken(token, Claims::getExpiration);
} }
public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) { private <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
final Claims claims = getAllClaimsFromToken(token); final Claims claims = getAllClaimsFromToken(token);
return claimsResolver.apply(claims); return claimsResolver.apply(claims);
} }
...@@ -103,6 +105,14 @@ public class JwtTokenUtil implements Serializable { ...@@ -103,6 +105,14 @@ public class JwtTokenUtil implements Serializable {
.compact(); .compact();
} }
public String getToken(HttpServletRequest request){
final String requestHeader = request.getHeader(tokenHeader);
if (requestHeader != null && requestHeader.startsWith("Bearer ")) {
return requestHeader.substring(7);
}
return null;
}
public Boolean validateToken(String token, UserDetails userDetails) { public Boolean validateToken(String token, UserDetails userDetails) {
JwtUser user = (JwtUser) userDetails; JwtUser user = (JwtUser) userDetails;
final Date created = getIssuedAtDateFromToken(token); final Date created = getIssuedAtDateFromToken(token);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment