commit
de3078ae9a
|
@ -1,6 +1,11 @@
|
|||
# Ignore Gradle project-specific cache directory
|
||||
.gradle
|
||||
*.iml
|
||||
application.properties
|
||||
application-*.properties
|
||||
|
||||
# Ignore Gradle build output directory
|
||||
build
|
||||
build/
|
||||
out/
|
||||
/.idea/
|
||||
gradle/
|
|
@ -35,7 +35,12 @@ subprojects {
|
|||
lombokVersion = "1.18.8"
|
||||
}
|
||||
dependencies {
|
||||
//gradle 4.7版本以上,使用如下方式
|
||||
// annotationProcessor("org.projectlombok:lombok:$lombokVersion")
|
||||
// compileOnly("org.projectlombok:lombok:$lombokVersion")
|
||||
//gradle 4.7版本以下,使用如下方式
|
||||
compileOnly("org.projectlombok:lombok:$lombokVersion")
|
||||
|
||||
compile("javax.servlet:javax.servlet-api:4.0.1")
|
||||
compile("org.springframework.boot:spring-boot-starter-web:$springBootVersion")
|
||||
// Mybatis
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
package diboot.core.test;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||
|
||||
/**
|
||||
* @author Administrator
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class StartupApplication extends SpringBootServletInitializer {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(StartupApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package diboot.core.test.config;
|
||||
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import com.alibaba.fastjson.support.config.FastJsonConfig;
|
||||
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
|
||||
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
|
||||
import com.diboot.core.util.D;
|
||||
import com.diboot.core.util.DateConverter;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.format.FormatterRegistry;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/***
|
||||
* Spring配置文件
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/6/10
|
||||
*/
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
@EnableTransactionManagement(proxyTargetClass=true)
|
||||
@ComponentScan(basePackages={"com.diboot"})
|
||||
@MapperScan({"com.diboot.**.mapper"})
|
||||
public class SpringMvcConfig implements WebMvcConfigurer{
|
||||
private static final Logger log = LoggerFactory.getLogger(SpringMvcConfig.class);
|
||||
|
||||
/**
|
||||
* JSON转换组件替换为fastJson
|
||||
*/
|
||||
@Bean
|
||||
public HttpMessageConverters fastJsonHttpMessageConverters() {
|
||||
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
|
||||
//处理中文乱码问题
|
||||
List<MediaType> fastMediaTypes = new ArrayList<>();
|
||||
fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
|
||||
converter.setSupportedMediaTypes(fastMediaTypes);
|
||||
// 配置转换格式
|
||||
FastJsonConfig fastJsonConfig = new FastJsonConfig();
|
||||
// 设置fastjson的序列化参数:禁用循环依赖检测,数据兼容浏览器端(避免JS端Long精度丢失问题)
|
||||
fastJsonConfig.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect,
|
||||
SerializerFeature.BrowserCompatible);
|
||||
fastJsonConfig.setDateFormat(D.FORMAT_DATETIME_Y4MDHM);
|
||||
converter.setFastJsonConfig(fastJsonConfig);
|
||||
|
||||
HttpMessageConverter<?> httpMsgConverter = converter;
|
||||
return new HttpMessageConverters(httpMsgConverter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFormatters(FormatterRegistry registry) {
|
||||
registry.addConverter(new DateConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Mybatis-plus分页插件
|
||||
*/
|
||||
@Bean
|
||||
public PaginationInterceptor paginationInterceptor() {
|
||||
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
|
||||
return paginationInterceptor;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package diboot.core.test.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.diboot.core.config.BaseConfig;
|
||||
import com.diboot.core.entity.Metadata;
|
||||
import com.diboot.core.service.MetadataService;
|
||||
import com.diboot.core.util.V;
|
||||
import com.diboot.core.vo.Pagination;
|
||||
import diboot.core.test.StartupApplication;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* BaseService接口实现测试 (需先执行example中的初始化SQL)
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/06/15
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = {StartupApplication.class})
|
||||
public class BaseServiceTest {
|
||||
|
||||
@Autowired
|
||||
MetadataService metadataService;
|
||||
|
||||
@Test
|
||||
public void testGet(){
|
||||
// 查询总数
|
||||
int count = metadataService.getEntityListCount(null);
|
||||
Assert.assertTrue(count > 0);
|
||||
// 查询list
|
||||
List<Metadata> metadataList = metadataService.getEntityList(null);
|
||||
Assert.assertTrue(V.notEmpty(metadataList));
|
||||
Assert.assertTrue(metadataList.size() == count);
|
||||
// 第一页数据
|
||||
List<Metadata> pageList = metadataService.getEntityList(null, new Pagination());
|
||||
Assert.assertTrue(pageList.size() > 0 && pageList.size() <= BaseConfig.getPageSize());
|
||||
|
||||
// 查询单个记录
|
||||
Long id = metadataList.get(0).getId();
|
||||
Metadata first = metadataService.getEntity(id);
|
||||
Assert.assertTrue(first != null);
|
||||
|
||||
// 只查询第一条记录对应type类型的
|
||||
LambdaQueryWrapper<Metadata> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(Metadata::getType, first.getType());
|
||||
metadataList = metadataService.getEntityList(queryWrapper);
|
||||
Assert.assertTrue(V.notEmpty(metadataList));
|
||||
// 结果type值一致
|
||||
metadataList.stream().forEach( m -> {
|
||||
Assert.assertTrue(m.getType().equals(first.getType()));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateUpdateAndDelete(){
|
||||
// 创建
|
||||
String TYPE = "ID_TYPE";
|
||||
Metadata metadata = new Metadata();
|
||||
metadata.setType(TYPE);
|
||||
metadata.setItemName("证件品类");
|
||||
metadata.setParentId(0L);
|
||||
metadataService.createEntity(metadata);
|
||||
|
||||
// 查询是否创建成功
|
||||
LambdaQueryWrapper<Metadata> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(Metadata::getType, TYPE);
|
||||
List<Metadata> metadataList = metadataService.getEntityList(queryWrapper);
|
||||
Assert.assertTrue(V.notEmpty(metadataList));
|
||||
|
||||
// 更新
|
||||
metadata.setItemName("证件类型");
|
||||
metadataService.updateEntity(metadata);
|
||||
Metadata metadata2 = metadataService.getEntity(metadata.getId());
|
||||
Assert.assertTrue(metadata2.getItemName().equals(metadata.getItemName()));
|
||||
|
||||
// 删除
|
||||
metadataService.deleteEntity(metadata.getId());
|
||||
metadata2 = metadataService.getEntity(metadata.getId());
|
||||
Assert.assertTrue(metadata2 == null);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,11 +1,3 @@
|
|||
server.port=8080
|
||||
server.servlet.context-path=/example
|
||||
#10秒超时
|
||||
spring.server.connectionTimeout=10000
|
||||
spring.server.protocol=org.apache.coyote.http11.Http11Nio2Protocol
|
||||
spring.server.redirectPort=443
|
||||
spring.server.compression=on
|
||||
|
||||
# spring config
|
||||
spring.devtools.restart.enabled=true
|
||||
|
||||
|
@ -19,11 +11,6 @@ spring.datasource.hikari.data-source-properties.nullCatalogMeansCurrent=true
|
|||
# 数据库驱动
|
||||
spring.datasource.hikari.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||
|
||||
#字符集utf-8
|
||||
spring.http.encoding.charset=UTF-8
|
||||
spring.http.encoding.enabled=true
|
||||
spring.http.encoding.force=true
|
||||
|
||||
# mybatis配置
|
||||
#mybatis.configuration.cache-enabled=false
|
||||
#mybatis.configuration.lazy-loading-enabled=true
|
||||
|
@ -42,4 +29,4 @@ logging.level.org.hibernate.validator=info
|
|||
logging.level.org.springframework=info
|
||||
logging.level.com.zaxxer.hikari=info
|
||||
logging.level.com.diboot=debug
|
||||
logging.level.org.mybatis=debug
|
||||
logging.level.org.mybatis=debug
|
|
@ -0,0 +1,5 @@
|
|||
__ _ __ __
|
||||
____/ / (_) / /_ ____ ____ / /_
|
||||
/ __ / / / / __ \ / __ \ / __ \ / __/
|
||||
/ /_/ / / / / /_/ / / /_/ / / /_/ / / /_
|
||||
\__,_/ /_/ /_.___/ \____/ \____/ \__/
|
|
@ -0,0 +1,24 @@
|
|||
## 我们使用了什么?
|
||||
* 这里的所有文档都使用vuepress这个工具来处理,关于vuepress的细节可以阅览[官方文档](https://vuepress.vuejs.org/zh/)。
|
||||
* 我们采用markdown来编写项目文档,如果您也要参与文档的贡献,也需要先了解markdown相关内容。
|
||||
## 我们应该怎样开始?
|
||||
1. 假设您本地已经安装了node环境,npm与yarn至少有其一了,那么打开命令行,我们先运行以下命令全局安装(已经安装过的不必再安装)vuepress:
|
||||
```bash
|
||||
yarn global add vuepress
|
||||
# 或者:
|
||||
npm install -g vuepress
|
||||
```
|
||||
2. 拉取该项目到本地,在命令行打开该目录下的相关文档目录。
|
||||
3. 运行以下命令,开始启动一个文档的server:
|
||||
```bash
|
||||
yarn serve
|
||||
# 或者:
|
||||
npm run serve
|
||||
```
|
||||
## 我们怎样存放静态文件?
|
||||
* 我们的图片文件以及其他类型的文件,建议存放在相应文档项目下的.vuepress/public/目录下。
|
||||
## 我们如何引入存放的静态文件?
|
||||
* 我们统一使用$withBase()方法来获取存放在.vuepress/public目录下的静态文件,示例如下:
|
||||
```markdown
|
||||
![图片]($withBase('/image.png'))
|
||||
```
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
title: 'diboot-core开发文档',
|
||||
description: 'diboot-core相关概念、接口、开发技巧相关的文档说明等。',
|
||||
base: '/diboot-core-docs/'
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
export default ({
|
||||
Vue, // VuePress 正在使用的 Vue 构造函数
|
||||
options, // 附加到根实例的一些选项
|
||||
router, // 当前应用的路由实例
|
||||
siteData // 站点元数据
|
||||
}) => {
|
||||
// 做相关的处理
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
# Hello VuePress!
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "diboot-core-docs",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"serve": "vuepress dev ./",
|
||||
"build": "vuepress build ./"
|
||||
},
|
||||
"author": "yang",
|
||||
"license": "Apache-2.0"
|
||||
}
|
|
@ -1,4 +1,7 @@
|
|||
dependencies {
|
||||
|
||||
compile project(":diboot-core")
|
||||
compile project(":diboot-shiro")
|
||||
|
||||
testCompile group: 'junit', name: 'junit', version: '4.12'
|
||||
}
|
|
@ -5,6 +5,7 @@ import com.alibaba.fastjson.support.config.FastJsonConfig;
|
|||
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
|
||||
import com.diboot.core.util.D;
|
||||
import com.diboot.core.util.DateConverter;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
|
@ -31,6 +32,7 @@ import java.util.List;
|
|||
@EnableAutoConfiguration
|
||||
@EnableTransactionManagement(proxyTargetClass=true)
|
||||
@ComponentScan(basePackages={"com.diboot"})
|
||||
@MapperScan({"com.diboot.*.mapper"})
|
||||
public class SpringMvcConfig implements WebMvcConfigurer{
|
||||
private static final Logger log = LoggerFactory.getLogger(SpringMvcConfig.class);
|
||||
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
package com.diboot.example.controller;
|
||||
|
||||
import com.diboot.core.vo.JsonResult;
|
||||
import com.diboot.core.vo.Status;
|
||||
import com.diboot.shiro.jwt.BaseJwtAuthenticationToken;
|
||||
import com.diboot.shiro.config.AuthType;
|
||||
import com.diboot.shiro.entity.SysUser;
|
||||
import com.diboot.shiro.service.AuthWayService;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/auth")
|
||||
public class AuthTokenController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AuthTokenController.class);
|
||||
|
||||
@Autowired
|
||||
private Map<String, AuthWayService> authWayServiceMap;
|
||||
|
||||
/***
|
||||
* 用户名密码登录接口
|
||||
* @param sysUser
|
||||
* @param request
|
||||
* @param response
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@PostMapping("/login")
|
||||
public JsonResult login(@RequestBody SysUser sysUser, HttpServletRequest request, HttpServletResponse response) throws Exception{
|
||||
String errorMsg = "登录失败";
|
||||
try{
|
||||
BaseJwtAuthenticationToken authToken = new BaseJwtAuthenticationToken(authWayServiceMap, sysUser.getUsername(), sysUser.getPassword(), AuthType.USERNAME_PASSWORD);
|
||||
Subject subject = SecurityUtils.getSubject();
|
||||
subject.login(authToken);
|
||||
|
||||
if (subject.isAuthenticated()){
|
||||
logger.debug("申请token成功!authtoken="+authToken.getCredentials());
|
||||
String token = (String)authToken.getCredentials();
|
||||
// 跳转到首页
|
||||
return new JsonResult(token, "Token申请成功");
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.error("登录失败", e);
|
||||
}
|
||||
|
||||
|
||||
return new JsonResult(Status.FAIL_INVALID_TOKEN, errorMsg);
|
||||
}
|
||||
|
||||
@PostMapping("/logout")
|
||||
public JsonResult logout(HttpServletRequest request, HttpServletResponse response) throws Exception{
|
||||
Subject subject = SecurityUtils.getSubject();
|
||||
if (subject.isAuthenticated() || subject.getPrincipals() != null){
|
||||
subject.logout();
|
||||
}
|
||||
|
||||
return new JsonResult(Status.OK, new String[]{"退出登录成功"});
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@ package com.diboot.example.controller;
|
|||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.diboot.core.binding.manager.AnnotationBindingManager;
|
||||
import com.diboot.core.controller.BaseCrudRestController;
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.core.util.BeanUtils;
|
||||
|
@ -14,6 +13,8 @@ import com.diboot.example.entity.Department;
|
|||
import com.diboot.example.entity.Organization;
|
||||
import com.diboot.example.service.DepartmentService;
|
||||
import com.diboot.example.vo.DepartmentVO;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.validation.BindingResult;
|
||||
|
@ -43,6 +44,7 @@ public class DepartmentController extends BaseCrudRestController {
|
|||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@RequiresPermissions("department:list")
|
||||
@GetMapping("/list")
|
||||
public JsonResult getVOList(HttpServletRequest request) throws Exception{
|
||||
QueryWrapper<Department> queryWrapper = buildQuery(request);
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
package com.diboot.example.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.diboot.core.util.V;
|
||||
import com.diboot.core.vo.JsonResult;
|
||||
import com.diboot.core.vo.Status;
|
||||
import com.diboot.shiro.entity.SysUser;
|
||||
import com.diboot.shiro.service.RoleService;
|
||||
import com.diboot.shiro.service.SysUserService;
|
||||
import com.diboot.shiro.util.JwtHelper;
|
||||
import com.diboot.shiro.vo.RoleVO;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/sysUser")
|
||||
public class SysUserController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SysUserController.class);
|
||||
|
||||
@Autowired
|
||||
private RoleService roleService;
|
||||
|
||||
@Autowired
|
||||
private SysUserService sysUserService;
|
||||
|
||||
/***
|
||||
* 获取登录用户信息
|
||||
* @param request
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@GetMapping("/info")
|
||||
public JsonResult info(HttpServletRequest request) throws Exception{
|
||||
String token = JwtHelper.getRequestToken(request);
|
||||
if (V.isEmpty(token)){
|
||||
return new JsonResult(Status.FAIL_OPERATION, new String[]{"获取数据失败"});
|
||||
}
|
||||
|
||||
String username = JwtHelper.getAccountFromToken(token);
|
||||
if (V.isEmpty(username)){
|
||||
return new JsonResult(Status.FAIL_OPERATION, new String[]{"获取数据失败"});
|
||||
}
|
||||
|
||||
QueryWrapper<SysUser> query = new QueryWrapper<>();
|
||||
query.lambda()
|
||||
.eq(SysUser::getUsername, username);
|
||||
List<SysUser> userList = sysUserService.getEntityList(query);
|
||||
if (V.isEmpty(userList)){
|
||||
return new JsonResult(Status.FAIL_OPERATION, new String[]{"获取数据失败"});
|
||||
}
|
||||
|
||||
SysUser user = userList.get(0);
|
||||
|
||||
List<RoleVO> roleVOList = roleService.getRelatedRoleAndPermissionListByUser(SysUser.class.getSimpleName(), user.getId());
|
||||
if (V.isEmpty(roleVOList)){
|
||||
return new JsonResult(Status.FAIL_OPERATION, new String[]{"获取用户角色失败"});
|
||||
}
|
||||
|
||||
user.setRoleVOList(roleVOList);
|
||||
|
||||
return new JsonResult(Status.OK, user, new String[]{"获取角色列表成功"});
|
||||
}
|
||||
}
|
|
@ -19,6 +19,9 @@ public class User extends BaseEntity {
|
|||
@TableField
|
||||
private String username;
|
||||
|
||||
@TableField
|
||||
private String password;
|
||||
|
||||
@TableField
|
||||
private String gender;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "./mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.diboot.example.mapper.OrganizationMapper">
|
||||
<mapper namespace="com.diboot.example.mapper.SysUserMapper">
|
||||
|
||||
</mapper>
|
|
@ -1,15 +0,0 @@
|
|||
package com.diboot.example.mapper;
|
||||
|
||||
import com.diboot.core.mapper.BaseCrudMapper;
|
||||
import com.diboot.example.entity.Role;
|
||||
|
||||
/**
|
||||
* 员工Mapper
|
||||
* @author Mazhicheng
|
||||
* @version 2018/12/22
|
||||
* Copyright © www.dibo.ltd
|
||||
*/
|
||||
public interface RoleMapper extends BaseCrudMapper<Role> {
|
||||
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
package com.diboot.example.service;
|
||||
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.example.entity.Role;
|
||||
|
||||
/**
|
||||
* 员工相关Service
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/5
|
||||
*/
|
||||
public interface RoleService extends BaseService<Role> {
|
||||
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package com.diboot.example.service.impl;
|
||||
|
||||
import com.diboot.core.service.impl.BaseServiceImpl;
|
||||
import com.diboot.example.entity.Role;
|
||||
import com.diboot.example.mapper.RoleMapper;
|
||||
import com.diboot.example.service.RoleService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 员工相关Service
|
||||
* @author Mazhicheng
|
||||
* @version 2018/12/23
|
||||
* Copyright © www.dibo.ltd
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class RoleServiceImpl extends BaseServiceImpl<RoleMapper, Role> implements RoleService {
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
/**
|
||||
* @author : wee
|
||||
* @Description: todo
|
||||
* @Date 2019-05-17 19:15
|
||||
*/
|
||||
public class MainTest {
|
||||
public static void main(String[] args) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.diboot.example;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class ApplicationTest {
|
||||
|
||||
@Test
|
||||
public void contextLoads(){
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package com.diboot.example.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.diboot.core.util.BeanUtils;
|
||||
import com.diboot.core.util.V;
|
||||
import com.diboot.example.ApplicationTest;
|
||||
import com.diboot.example.entity.Department;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
@Component
|
||||
public class DepartmentServiceTest extends ApplicationTest {
|
||||
|
||||
@Autowired
|
||||
private DepartmentService departmentService;
|
||||
|
||||
@Test
|
||||
public void getEntityListTest() throws Exception{
|
||||
QueryWrapper<Department> query = new QueryWrapper<>();
|
||||
query.eq(BeanUtils.convertToFieldName(Department::getName), "研发部");
|
||||
List<Department> departmentList = departmentService.getEntityList(query);
|
||||
Assert.assertTrue(V.notEmpty(departmentList));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
dependencies {
|
||||
compile project(":diboot-core")
|
||||
|
||||
compile("org.apache.shiro:shiro-spring:1.4.1")
|
||||
compile("com.auth0:java-jwt:3.4.1",
|
||||
"io.jsonwebtoken:jjwt:0.9.1")
|
||||
|
||||
testCompile group: 'junit', name: 'junit', version: '4.12'
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.diboot.shiro.bind.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* controller上注解,用于标记权限的菜单分类
|
||||
* @author : wee
|
||||
* @version v2.0
|
||||
* @Date 2019-06-14 23:00
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface PermissionsMenu {
|
||||
/**
|
||||
* 菜单编码
|
||||
* @return
|
||||
*/
|
||||
String menuCode();
|
||||
/**
|
||||
* 菜单名称
|
||||
* @return
|
||||
*/
|
||||
String menuName();
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package com.diboot.shiro.bind.annotation;
|
||||
|
||||
import org.apache.shiro.authz.annotation.Logical;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 注解{@link RequiresPermissions}的增强注解,增加权限描述等字段
|
||||
* @author : wee
|
||||
* @version v2.0
|
||||
* @Date 2019-06-14 17:50
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
@RequiresPermissions("default")
|
||||
public @interface RequiresPermissionsProxy {
|
||||
|
||||
/**
|
||||
* 代理 {@link RequiresPermissions#value()}
|
||||
*/
|
||||
String[] value();
|
||||
|
||||
/**
|
||||
* 代理 {@link RequiresPermissions#logical()}
|
||||
*/
|
||||
Logical logical() default Logical.AND;
|
||||
|
||||
/**
|
||||
* 菜单编码
|
||||
* @return
|
||||
*/
|
||||
String menuCode();
|
||||
/**
|
||||
* 菜单名称
|
||||
* @return
|
||||
*/
|
||||
String menuName();
|
||||
|
||||
/**
|
||||
* 权限名称
|
||||
* @return
|
||||
*/
|
||||
String permissionName();
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package com.diboot.shiro.bind.aop;
|
||||
|
||||
import com.diboot.shiro.bind.annotation.RequiresPermissionsProxy;
|
||||
import com.diboot.shiro.bind.handler.PermissionProxyAnnotationHandler;
|
||||
import org.apache.shiro.aop.AnnotationResolver;
|
||||
import org.apache.shiro.authz.aop.AuthorizingAnnotationMethodInterceptor;
|
||||
|
||||
/**
|
||||
* {@link RequiresPermissionsProxy} 拦截器
|
||||
* @author : wee
|
||||
* @version : v2.0
|
||||
* @Date 2019-06-14 22:19
|
||||
*/
|
||||
public class PermissionProxyAnnotationMethodInterceptor extends AuthorizingAnnotationMethodInterceptor {
|
||||
/**
|
||||
* Default no-argument constructor that ensures this interceptor looks for
|
||||
* {@link org.apache.shiro.authz.annotation.RequiresPermissions RequiresPermissions} annotations in a method declaration.
|
||||
*/
|
||||
public PermissionProxyAnnotationMethodInterceptor() {
|
||||
super( new PermissionProxyAnnotationHandler() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param resolver
|
||||
* @since 1.1
|
||||
*/
|
||||
public PermissionProxyAnnotationMethodInterceptor(AnnotationResolver resolver) {
|
||||
super( new PermissionProxyAnnotationHandler(), resolver);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package com.diboot.shiro.bind.handler;
|
||||
|
||||
import com.diboot.shiro.bind.annotation.RequiresPermissionsProxy;
|
||||
import org.apache.shiro.aop.AnnotationResolver;
|
||||
import org.apache.shiro.authz.AuthorizationException;
|
||||
import org.apache.shiro.authz.annotation.Logical;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||
import org.apache.shiro.authz.aop.AuthorizingAnnotationHandler;
|
||||
import org.apache.shiro.authz.aop.AuthorizingAnnotationMethodInterceptor;
|
||||
import org.apache.shiro.authz.aop.PermissionAnnotationHandler;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* {@link RequiresPermissionsProxy} 助手类, 参考{@link PermissionAnnotationHandler}实现
|
||||
* @author : wee
|
||||
* @version : v2.0
|
||||
* @Date 2019-06-14 22:19
|
||||
*/
|
||||
public class PermissionProxyAnnotationHandler extends AuthorizingAnnotationHandler {
|
||||
|
||||
private final static String REQUIRES_PERMISSIONS_VALUE = "value";
|
||||
|
||||
private final static String REQUIRES_PERMISSIONS_LOGICAL = "logical";
|
||||
|
||||
private final static String JDK_MEMBER_VALUES = "memberValues";
|
||||
|
||||
/**
|
||||
* 标记服务的注解
|
||||
*/
|
||||
public PermissionProxyAnnotationHandler() {
|
||||
super(RequiresPermissionsProxy.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将{@link RequiresPermissionsProxy} 代理的内容赋值给{@link RequiresPermissions}
|
||||
*/
|
||||
@Override
|
||||
public void assertAuthorized(Annotation a) throws AuthorizationException {
|
||||
if (!(a instanceof RequiresPermissionsProxy)) {
|
||||
return;
|
||||
}
|
||||
RequiresPermissionsProxy rrAnnotation = (RequiresPermissionsProxy) a;
|
||||
try {
|
||||
//获取RequiresPermissionsProxy上的RequiresPermissions注解
|
||||
RequiresPermissions requiresPermissions = rrAnnotation.annotationType().getAnnotation(RequiresPermissions.class);
|
||||
|
||||
InvocationHandler invocationHandler = Proxy.getInvocationHandler(requiresPermissions);
|
||||
/* memberValues 为JDK中存储所有成员变量值的Map {@link AnnotationInvocationHandler#memberValues}*/
|
||||
Field jdkValue = invocationHandler.getClass().getDeclaredField(JDK_MEMBER_VALUES);
|
||||
jdkValue.setAccessible(true);
|
||||
/*获取RequiresPermissions对应的代理属性值*/
|
||||
Map<String, Object> memberValues = (Map<String, Object>) jdkValue.get(invocationHandler);
|
||||
/*动态设置RequiresPermissions注解的内容*/
|
||||
memberValues.put(REQUIRES_PERMISSIONS_VALUE, rrAnnotation.value());
|
||||
memberValues.put(REQUIRES_PERMISSIONS_LOGICAL, rrAnnotation.logical());
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package com.diboot.shiro.config;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/***
|
||||
* 认证方式
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
public enum AuthType {
|
||||
|
||||
USERNAME_PASSWORD(1, true, "账号密码"),
|
||||
WX_MP(2, false, "公众号"),
|
||||
WX_CP(3, false, "企业微信");
|
||||
|
||||
private AuthType(int code, boolean requirePassword, String label){
|
||||
this.code = code;
|
||||
this.requirePassword = requirePassword;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
private int code;
|
||||
private boolean requirePassword;
|
||||
private String label;
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public boolean isRequirePassword() {
|
||||
return requirePassword;
|
||||
}
|
||||
|
||||
public void setRequirePassword(boolean requirePassword) {
|
||||
this.requirePassword = requirePassword;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public void setLabel(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
package com.diboot.shiro.config;
|
||||
|
||||
import com.diboot.shiro.bind.aop.PermissionProxyAnnotationMethodInterceptor;
|
||||
import com.diboot.shiro.jwt.BaseJwtAuthenticationFilter;
|
||||
import com.diboot.shiro.jwt.BaseJwtRealm;
|
||||
import org.apache.shiro.aop.AnnotationResolver;
|
||||
import org.apache.shiro.authz.aop.*;
|
||||
import org.apache.shiro.mgt.SecurityManager;
|
||||
import org.apache.shiro.realm.Realm;
|
||||
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
|
||||
import org.apache.shiro.spring.aop.SpringAnnotationResolver;
|
||||
import org.apache.shiro.spring.security.interceptor.AopAllianceAnnotationsAuthorizingMethodInterceptor;
|
||||
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
|
||||
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
|
||||
import org.apache.shiro.web.filter.authc.AnonymousFilter;
|
||||
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/***
|
||||
*
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
@Configuration
|
||||
public class ShiroConfig {
|
||||
private static final Logger logger = LoggerFactory.getLogger(ShiroConfig.class);
|
||||
|
||||
@Bean
|
||||
public Realm realm(){
|
||||
BaseJwtRealm realm = new BaseJwtRealm();
|
||||
return realm;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityManager securityManager(){
|
||||
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
|
||||
securityManager.setRealm(realm());
|
||||
return securityManager;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
|
||||
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
|
||||
|
||||
//Shiro securityManager
|
||||
shiroFilterFactoryBean.setSecurityManager(securityManager);
|
||||
|
||||
//用户访问未对其授权的资源时的错误提示页面
|
||||
shiroFilterFactoryBean.setUnauthorizedUrl("/error");
|
||||
|
||||
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
|
||||
|
||||
filterChainDefinitionMap.put("/", "anon");
|
||||
filterChainDefinitionMap.put("/static/**", "anon");
|
||||
filterChainDefinitionMap.put("/auth/login", "anon");
|
||||
filterChainDefinitionMap.put("/error", "anon");
|
||||
filterChainDefinitionMap.put("/auth/logout", "logout");
|
||||
filterChainDefinitionMap.put("/**", "jwt");
|
||||
|
||||
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
|
||||
|
||||
// 设置过滤器
|
||||
Map<String, Filter> filters = new LinkedHashMap<>();
|
||||
filters.put("anon", new AnonymousFilter());
|
||||
filters.put("jwt", new BaseJwtAuthenticationFilter());
|
||||
shiroFilterFactoryBean.setFilters(filters);
|
||||
|
||||
return shiroFilterFactoryBean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shiro生命周期处理器
|
||||
*/
|
||||
@Bean
|
||||
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
|
||||
return new LifecycleBeanPostProcessor();
|
||||
}
|
||||
|
||||
/***
|
||||
* 以下两个为使用注解权限相关的配置
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
@DependsOn({"lifecycleBeanPostProcessor"})
|
||||
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
|
||||
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
|
||||
advisorAutoProxyCreator.setProxyTargetClass(true);
|
||||
return advisorAutoProxyCreator;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
|
||||
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
|
||||
AopAllianceAnnotationsAuthorizingMethodInterceptor advice = (AopAllianceAnnotationsAuthorizingMethodInterceptor)authorizationAttributeSourceAdvisor.getAdvice();
|
||||
//重置拦截器,添加新的PermissionProxyAnnotationMethodInterceptor
|
||||
List<AuthorizingAnnotationMethodInterceptor> interceptors =new ArrayList<>(6);
|
||||
AnnotationResolver resolver = new SpringAnnotationResolver();
|
||||
interceptors.add(new PermissionProxyAnnotationMethodInterceptor(resolver));
|
||||
interceptors.add(new RoleAnnotationMethodInterceptor(resolver));
|
||||
interceptors.add(new PermissionAnnotationMethodInterceptor(resolver));
|
||||
interceptors.add(new AuthenticatedAnnotationMethodInterceptor(resolver));
|
||||
interceptors.add(new UserAnnotationMethodInterceptor(resolver));
|
||||
interceptors.add(new GuestAnnotationMethodInterceptor(resolver));
|
||||
advice.setMethodInterceptors(interceptors);
|
||||
|
||||
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
|
||||
return authorizationAttributeSourceAdvisor;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
package com.diboot.shiro.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.diboot.core.controller.BaseCrudRestController;
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.core.util.BeanUtils;
|
||||
import com.diboot.core.vo.JsonResult;
|
||||
import com.diboot.core.vo.Pagination;
|
||||
import com.diboot.core.vo.Status;
|
||||
import com.diboot.shiro.bind.annotation.PermissionsMenu;
|
||||
import com.diboot.shiro.bind.annotation.RequiresPermissionsProxy;
|
||||
import com.diboot.shiro.entity.Permission;
|
||||
import com.diboot.shiro.service.PermissionService;
|
||||
import com.diboot.shiro.vo.PermissionVO;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Organization相关Controller
|
||||
* @author Mazhicheng
|
||||
* @version 2018/12/23
|
||||
* Copyright © www.dibo.ltd
|
||||
*/
|
||||
@PermissionsMenu(menuName = "权限", menuCode = "permission")
|
||||
@RestController
|
||||
@RequestMapping("/permission")
|
||||
public class PermissionController extends BaseCrudRestController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PermissionService.class);
|
||||
|
||||
@Autowired
|
||||
private PermissionService permissionService;
|
||||
|
||||
/***
|
||||
* 查询ViewObject的分页数据 (此为非继承的自定义使用案例,更简化的调用父类案例请参考UserController)
|
||||
* <p>
|
||||
* url参数示例: /list?_pageSize=20&_pageIndex=1&_orderBy=id&code=TST
|
||||
* </p>
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
@RequiresPermissionsProxy(value = {"permission:list"}, menuCode = "permission",
|
||||
menuName = "权限", permissionName = "列表")
|
||||
public JsonResult getVOList(HttpServletRequest request) throws Exception{
|
||||
QueryWrapper<Permission> queryWrapper = buildQuery(request);
|
||||
// 构建分页
|
||||
Pagination pagination = buildPagination(request);
|
||||
// 查询当前页的Entity主表数据
|
||||
List entityList = getService().getEntityList(queryWrapper, pagination);
|
||||
// 自动转换VO中注解绑定的关联
|
||||
List<PermissionVO> voList = super.convertToVoAndBindRelations(entityList, PermissionVO.class);
|
||||
|
||||
return new JsonResult(Status.OK, voList).bindPagination(pagination);
|
||||
}
|
||||
|
||||
/***
|
||||
* 创建Entity
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@RequiresPermissions("permission:add")
|
||||
@PostMapping("/")
|
||||
public JsonResult createEntity(@ModelAttribute PermissionVO viewObject, BindingResult result, HttpServletRequest request, ModelMap modelMap)
|
||||
throws Exception{
|
||||
// 转换
|
||||
Permission entity = BeanUtils.convert(viewObject, Permission.class);
|
||||
// 创建
|
||||
return super.createEntity(entity, result, modelMap);
|
||||
}
|
||||
|
||||
/***
|
||||
* 查询Entity
|
||||
* @param id ID
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
@RequiresPermissionsProxy(value = {"permission:get"}, menuCode = "permission", menuName = "权限", permissionName = "查看")
|
||||
public JsonResult getModel(@PathVariable("id")Long id, HttpServletRequest request, ModelMap modelMap)
|
||||
throws Exception{
|
||||
PermissionVO vo = permissionService.getViewObject(id, PermissionVO.class);
|
||||
return new JsonResult(vo);
|
||||
}
|
||||
|
||||
/***
|
||||
* 更新Entity
|
||||
* @param id ID
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@RequiresPermissions("permission:update")
|
||||
@PutMapping("/{id}")
|
||||
public JsonResult updateModel(@PathVariable("id")Long id, @ModelAttribute Permission entity, BindingResult result,
|
||||
HttpServletRequest request, ModelMap modelMap) throws Exception{
|
||||
return super.updateEntity(entity, result, modelMap);
|
||||
}
|
||||
|
||||
/***
|
||||
* 删除用户
|
||||
* @param id 用户ID
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@RequiresPermissions("permission:delete")
|
||||
@DeleteMapping("/{id}")
|
||||
public JsonResult deleteModel(@PathVariable("id")Long id, HttpServletRequest request) throws Exception{
|
||||
return super.deleteEntity(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BaseService getService() {
|
||||
return permissionService;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package com.diboot.shiro.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
@Data
|
||||
public class Permission extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 7713768302925692987L;
|
||||
|
||||
@TableField
|
||||
private String menuCode;
|
||||
|
||||
@TableField
|
||||
private String menuName;
|
||||
|
||||
@TableField
|
||||
private String permissionCode;
|
||||
|
||||
@TableField
|
||||
private String permissionName;
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package com.diboot.shiro.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
@Data
|
||||
public class Role extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 5433209472424293571L;
|
||||
|
||||
@TableField
|
||||
private String name;
|
||||
|
||||
@TableField
|
||||
private String code;
|
||||
|
||||
@TableField(exist = false)
|
||||
private List<Permission> permissionList;
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.diboot.shiro.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
@Data
|
||||
public class RolePermission extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = -710604862356186012L;
|
||||
|
||||
@TableField
|
||||
private Long roleId;
|
||||
|
||||
@TableField
|
||||
private Long permissionId;
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package com.diboot.shiro.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import com.diboot.shiro.vo.RoleVO;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
@Data
|
||||
public class SysUser extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 466801280426981780L;
|
||||
|
||||
@TableField
|
||||
private Long departmentId;
|
||||
|
||||
@TableField
|
||||
private String username;
|
||||
|
||||
@TableField
|
||||
private String password;
|
||||
|
||||
@TableField
|
||||
private String gender;
|
||||
|
||||
@TableField(exist = false)
|
||||
private List<Role> roleList;
|
||||
|
||||
@TableField(exist = false)
|
||||
private List<RoleVO> roleVOList;
|
||||
|
||||
@TableField(exist = false)
|
||||
private List<Permission> permissionList;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.diboot.shiro.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
@Data
|
||||
public class UserRole extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 6415425761451054775L;
|
||||
|
||||
@TableField
|
||||
private String userType;
|
||||
|
||||
@TableField
|
||||
private Long userId;
|
||||
|
||||
@TableField
|
||||
private Long roleId;
|
||||
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package com.diboot.shiro.jwt;
|
||||
|
||||
import com.diboot.core.util.JSON;
|
||||
import com.diboot.core.util.V;
|
||||
import com.diboot.core.vo.JsonResult;
|
||||
import com.diboot.core.vo.Status;
|
||||
import com.diboot.shiro.util.JwtHelper;
|
||||
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* JWT 认证过滤器
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
public class BaseJwtAuthenticationFilter extends BasicHttpAuthenticationFilter {
|
||||
private static final Logger logger = LoggerFactory.getLogger(BaseJwtAuthenticationFilter.class);
|
||||
|
||||
/**
|
||||
* Shiro权限拦截核心方法 返回true允许访问,这里使用JWT进行认证
|
||||
*/
|
||||
@Override
|
||||
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||
// 获取Token
|
||||
String accessToken = JwtHelper.getRequestToken(httpRequest);
|
||||
if (V.isEmpty(accessToken)) {
|
||||
logger.warn("Token为空!url="+httpRequest.getRequestURL());
|
||||
return false;
|
||||
}
|
||||
//获取username
|
||||
String account = JwtHelper.getAccountFromToken(accessToken);
|
||||
if(V.notEmpty(account)){
|
||||
logger.debug("Token认证成功!account="+account);
|
||||
return true;
|
||||
}
|
||||
logger.debug("Token认证失败!");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当访问拒绝时是否已经处理了;如果返回true表示需要继续处理;如果返回false表示该拦截器实例已经处理
|
||||
* @param
|
||||
*/
|
||||
@Override
|
||||
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
|
||||
logger.debug("Token认证: onAccessDenied");
|
||||
JsonResult jsonResult = new JsonResult(Status.FAIL_INVALID_TOKEN);
|
||||
this.responseJson((HttpServletResponse) response, jsonResult);
|
||||
return false;
|
||||
}
|
||||
|
||||
/***
|
||||
* 返回json格式错误信息
|
||||
* @param response
|
||||
* @param jsonResult
|
||||
*/
|
||||
protected void responseJson(HttpServletResponse response, JsonResult jsonResult){
|
||||
// 处理异步请求
|
||||
PrintWriter pw = null;
|
||||
try {
|
||||
response.setStatus(HttpStatus.OK.value());
|
||||
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
|
||||
pw = response.getWriter();
|
||||
pw.write(JSON.stringify(jsonResult));
|
||||
pw.flush();
|
||||
}
|
||||
catch (IOException e) {
|
||||
logger.error("处理异步请求异常", e);
|
||||
}
|
||||
finally {
|
||||
if (pw != null) {
|
||||
pw.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,207 @@
|
|||
package com.diboot.shiro.jwt;
|
||||
|
||||
import com.diboot.core.util.V;
|
||||
import com.diboot.shiro.config.AuthType;
|
||||
import com.diboot.shiro.service.AuthWayService;
|
||||
import com.diboot.shiro.util.JwtHelper;
|
||||
import org.apache.shiro.authc.AuthenticationToken;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
@Component
|
||||
public class BaseJwtAuthenticationToken implements AuthenticationToken {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(BaseJwtAuthenticationToken.class);
|
||||
|
||||
// 登录用的账号(此处的这个账号是一种抽象的概念)
|
||||
private String account;
|
||||
|
||||
// 登录用的密码 (此处的这个密码也是一种抽象的概念)
|
||||
private String password;
|
||||
|
||||
// 登录使用方式
|
||||
private AuthType authType;
|
||||
|
||||
// auth token
|
||||
private String authtoken;
|
||||
|
||||
// 申请token的密码
|
||||
private String applyTokenSecret;
|
||||
|
||||
// 签名key (默认SIGN_KEY,配置signKey, 或微信state, 密码等)
|
||||
private String signKey = JwtHelper.SIGN_KEY;
|
||||
|
||||
// 过期时间
|
||||
private long expiresInMinutes = JwtHelper.EXPIRES_IN_MINUTES;
|
||||
|
||||
private Map<String, AuthWayService> authWayServiceMap;
|
||||
|
||||
// 默认构造函数
|
||||
public BaseJwtAuthenticationToken(){
|
||||
|
||||
}
|
||||
|
||||
public BaseJwtAuthenticationToken(Map<String, AuthWayService> authWayServiceMap){
|
||||
this.authWayServiceMap = authWayServiceMap;
|
||||
}
|
||||
|
||||
/***
|
||||
* 用户名码形式的授权
|
||||
* @param account
|
||||
* @param password
|
||||
*/
|
||||
public BaseJwtAuthenticationToken(Map<String, AuthWayService> authWayServiceMap, String account, String password){
|
||||
this.authWayServiceMap = authWayServiceMap;
|
||||
this.account = account;
|
||||
this.password = password;
|
||||
// 设置为默认登录方式
|
||||
this.authType = AuthType.USERNAME_PASSWORD;
|
||||
|
||||
this.initJwtAuthenticationToken(account, signKey, false);
|
||||
}
|
||||
|
||||
/***
|
||||
* 以用户名密码这类形式的其他类型授权
|
||||
* @param account
|
||||
* @param password
|
||||
* @param authType
|
||||
*/
|
||||
public BaseJwtAuthenticationToken(Map<String, AuthWayService> authWayServiceMap, String account, String password, AuthType authType){
|
||||
this.authWayServiceMap = authWayServiceMap;
|
||||
this.account = account;
|
||||
this.password = password;
|
||||
this.authType = authType;
|
||||
|
||||
this.initJwtAuthenticationToken(account, signKey, getAuthWayService().isPreliminaryVerified());
|
||||
}
|
||||
|
||||
/***
|
||||
* 其他授权种类的适配构造函数
|
||||
* @param account
|
||||
* @param authType
|
||||
*/
|
||||
public BaseJwtAuthenticationToken(Map<String, AuthWayService> authWayServiceMap, String account, AuthType authType){
|
||||
this.authWayServiceMap = authWayServiceMap;
|
||||
this.account = account;
|
||||
this.authType = authType;
|
||||
|
||||
this.initJwtAuthenticationToken(account, signKey, getAuthWayService().isPreliminaryVerified());
|
||||
}
|
||||
|
||||
public AuthWayService getAuthWayService(){
|
||||
|
||||
if (V.notEmpty(authWayServiceMap)){
|
||||
|
||||
for (AuthWayService authWayService : authWayServiceMap.values()){
|
||||
if (authWayService.authType() == authType){
|
||||
authWayService.initByToken(this);
|
||||
return authWayService;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/***
|
||||
* 初始化认证token
|
||||
* @param account
|
||||
* @param password
|
||||
* @param preliminaryVerified
|
||||
*/
|
||||
private void initJwtAuthenticationToken(String account, String password, boolean preliminaryVerified){
|
||||
if(this.account != null){
|
||||
Long expiresInMinutes = this.getAuthWayService().getExpiresInMinutes();
|
||||
this.expiresInMinutes = V.notEmpty(expiresInMinutes) ? expiresInMinutes : this.expiresInMinutes;
|
||||
this.authtoken = JwtHelper.generateToken(this.account, this.signKey, this.expiresInMinutes);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrincipal() {
|
||||
return account;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCredentials() {
|
||||
return authtoken;
|
||||
}
|
||||
|
||||
public String getApplyTokenSecret() {
|
||||
return applyTokenSecret;
|
||||
}
|
||||
|
||||
/***
|
||||
* 验证失败的时候清空token
|
||||
*/
|
||||
public void clearAuthtoken(){
|
||||
this.authtoken = null;
|
||||
}
|
||||
|
||||
public void setApplyTokenSecret(String applyTokenSecret) {
|
||||
this.applyTokenSecret = applyTokenSecret;
|
||||
}
|
||||
|
||||
public String getSignKey() {
|
||||
return signKey;
|
||||
}
|
||||
|
||||
public void setSignKey(String signKey) {
|
||||
this.signKey = signKey;
|
||||
}
|
||||
|
||||
public String getAccount() {
|
||||
return account;
|
||||
}
|
||||
|
||||
public void setAccount(String account) {
|
||||
this.account = account;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public AuthType getAuthType() {
|
||||
return authType;
|
||||
}
|
||||
|
||||
public void setAuthType(AuthType authType) {
|
||||
this.authType = authType;
|
||||
}
|
||||
|
||||
public String getAuthtoken() {
|
||||
return authtoken;
|
||||
}
|
||||
|
||||
public void setAuthtoken(String authtoken) {
|
||||
this.authtoken = authtoken;
|
||||
}
|
||||
|
||||
public long getExpiresInMinutes() {
|
||||
return expiresInMinutes;
|
||||
}
|
||||
|
||||
public void setExpiresInMinutes(long expiresInMinutes) {
|
||||
this.expiresInMinutes = expiresInMinutes;
|
||||
}
|
||||
|
||||
public Map<String, AuthWayService> getAuthWayServiceMap() {
|
||||
return authWayServiceMap;
|
||||
}
|
||||
|
||||
public void setAuthWayServiceMap(Map<String, AuthWayService> authWayServiceMap) {
|
||||
this.authWayServiceMap = authWayServiceMap;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
package com.diboot.shiro.jwt;
|
||||
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import com.diboot.core.util.V;
|
||||
import com.diboot.shiro.entity.Permission;
|
||||
import com.diboot.shiro.service.*;
|
||||
import com.diboot.shiro.vo.RoleVO;
|
||||
import org.apache.shiro.authc.AuthenticationException;
|
||||
import org.apache.shiro.authc.AuthenticationInfo;
|
||||
import org.apache.shiro.authc.AuthenticationToken;
|
||||
import org.apache.shiro.authc.SimpleAuthenticationInfo;
|
||||
import org.apache.shiro.authz.AuthorizationInfo;
|
||||
import org.apache.shiro.authz.SimpleAuthorizationInfo;
|
||||
import org.apache.shiro.realm.AuthorizingRealm;
|
||||
import org.apache.shiro.subject.PrincipalCollection;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
public class BaseJwtRealm extends AuthorizingRealm {
|
||||
|
||||
@Autowired
|
||||
private UserRoleService userRoleService;
|
||||
|
||||
@Autowired
|
||||
private RoleService roleService;
|
||||
|
||||
public boolean supports(AuthenticationToken token) {
|
||||
return token != null && token instanceof BaseJwtAuthenticationToken;
|
||||
}
|
||||
|
||||
|
||||
public Class<?> getAuthenticationTokenClass() {
|
||||
return BaseJwtRealm.class;
|
||||
}
|
||||
|
||||
/***
|
||||
* 认证
|
||||
* @param token
|
||||
* @return
|
||||
* @throws AuthenticationException
|
||||
*/
|
||||
@Override
|
||||
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
|
||||
BaseJwtAuthenticationToken jwtToken = (BaseJwtAuthenticationToken) token;
|
||||
|
||||
String account = (String) jwtToken.getPrincipal();
|
||||
|
||||
if (V.isEmpty(account)){
|
||||
throw new AuthenticationException("无效的token");
|
||||
}
|
||||
else {
|
||||
// 获取认证方式
|
||||
AuthWayService authWayService = jwtToken.getAuthWayService();
|
||||
|
||||
BaseEntity user = authWayService.getUser();
|
||||
|
||||
// 登录失败则抛出相关异常
|
||||
if (user == null){
|
||||
throw new AuthenticationException("用户不存在");
|
||||
}
|
||||
|
||||
if (authWayService.requirePassword() && !authWayService.isPasswordMatch()){
|
||||
throw new AuthenticationException("用户名或密码错误");
|
||||
}
|
||||
return new SimpleAuthenticationInfo(user, jwtToken.getCredentials(), this.getName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* 授权
|
||||
* @param principals
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
|
||||
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
|
||||
|
||||
// 获取用户类型
|
||||
String userType = principals.getPrimaryPrincipal().getClass().getSimpleName();
|
||||
BaseEntity user = (BaseEntity) principals.getPrimaryPrincipal();
|
||||
|
||||
// 根据用户类型与用户id获取roleList
|
||||
List<RoleVO> roleVOList = roleService.getRelatedRoleAndPermissionListByUser(userType, user.getId());
|
||||
|
||||
if (V.isEmpty(roleVOList)){
|
||||
return authorizationInfo;
|
||||
}
|
||||
|
||||
// 整理所有权限许可列表
|
||||
Set<String> allStringRoleList = new HashSet<>();
|
||||
Set<String> allStringPermissionList = new HashSet<>();
|
||||
for (RoleVO roleVO : roleVOList){
|
||||
// 添加当前角色到角色列表中
|
||||
allStringRoleList.add(roleVO.getCode());
|
||||
|
||||
if (V.isEmpty(roleVO.getPermissionList())){
|
||||
continue;
|
||||
}
|
||||
|
||||
// 添加当前所有权限许可到权限许可列表
|
||||
List stringPermissionList = roleVO.getPermissionList().stream()
|
||||
.map(Permission::getPermissionCode)
|
||||
.collect(Collectors.toList());
|
||||
allStringPermissionList.addAll(stringPermissionList);
|
||||
}
|
||||
|
||||
// 将所有角色和权限许可授权给用户
|
||||
authorizationInfo.setRoles(allStringRoleList);
|
||||
authorizationInfo.setStringPermissions(allStringPermissionList);
|
||||
|
||||
return authorizationInfo;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.diboot.shiro.mapper;
|
||||
|
||||
import com.diboot.core.mapper.BaseCrudMapper;
|
||||
import com.diboot.shiro.entity.Permission;
|
||||
|
||||
/**
|
||||
* 授权Mapper
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
public interface PermissionMapper extends BaseCrudMapper<Permission> {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "./mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.diboot.shiro.mapper.PermissionMapper">
|
||||
|
||||
</mapper>
|
|
@ -0,0 +1,15 @@
|
|||
package com.diboot.shiro.mapper;
|
||||
|
||||
import com.diboot.core.mapper.BaseCrudMapper;
|
||||
import com.diboot.shiro.entity.Role;
|
||||
|
||||
/**
|
||||
* 角色Mapper
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
public interface RoleMapper extends BaseCrudMapper<Role> {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "./mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.diboot.shiro.mapper.RoleMapper">
|
||||
|
||||
</mapper>
|
|
@ -0,0 +1,15 @@
|
|||
package com.diboot.shiro.mapper;
|
||||
|
||||
import com.diboot.core.mapper.BaseCrudMapper;
|
||||
import com.diboot.shiro.entity.RolePermission;
|
||||
|
||||
/**
|
||||
* 角色授权Mapper
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
public interface RolePermissionMapper extends BaseCrudMapper<RolePermission> {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "./mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.diboot.shiro.mapper.RolePermissionMapper">
|
||||
|
||||
</mapper>
|
|
@ -0,0 +1,15 @@
|
|||
package com.diboot.shiro.mapper;
|
||||
|
||||
import com.diboot.core.mapper.BaseCrudMapper;
|
||||
import com.diboot.shiro.entity.SysUser;
|
||||
|
||||
/**
|
||||
* 用户Mapper
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
public interface SysUserMapper extends BaseCrudMapper<SysUser> {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "./mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.diboot.shiro.mapper.SysUserMapper">
|
||||
|
||||
</mapper>
|
|
@ -0,0 +1,15 @@
|
|||
package com.diboot.shiro.mapper;
|
||||
|
||||
import com.diboot.core.mapper.BaseCrudMapper;
|
||||
import com.diboot.shiro.entity.UserRole;
|
||||
|
||||
/**
|
||||
* 用户角色Mapper
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
public interface UserRoleMapper extends BaseCrudMapper<UserRole> {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "./mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.diboot.shiro.mapper.UserRoleMapper">
|
||||
|
||||
</mapper>
|
|
@ -0,0 +1,56 @@
|
|||
package com.diboot.shiro.service;
|
||||
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import com.diboot.shiro.jwt.BaseJwtAuthenticationToken;
|
||||
import com.diboot.shiro.config.AuthType;
|
||||
|
||||
/***
|
||||
* 认证方式接口
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
public interface AuthWayService {
|
||||
|
||||
/***
|
||||
* 获取认证类型
|
||||
* @return
|
||||
*/
|
||||
AuthType authType();
|
||||
|
||||
/***
|
||||
* 根据令牌初始化认证方式
|
||||
* @param token
|
||||
*/
|
||||
void initByToken(BaseJwtAuthenticationToken token);
|
||||
|
||||
/***
|
||||
* 获取用户信息
|
||||
* @return
|
||||
*/
|
||||
BaseEntity getUser();
|
||||
|
||||
/***
|
||||
* 是否需要密码
|
||||
* @return
|
||||
*/
|
||||
boolean requirePassword();
|
||||
|
||||
/***
|
||||
* 密码是否匹配
|
||||
* @return
|
||||
*/
|
||||
boolean isPasswordMatch();
|
||||
|
||||
/***
|
||||
* 是否已初步验证(如果没有初步验证,则在验证过程中会再次验证)
|
||||
* @return
|
||||
*/
|
||||
boolean isPreliminaryVerified();
|
||||
|
||||
/***
|
||||
* 获取该认证方式过期时间(分钟)
|
||||
* @return
|
||||
*/
|
||||
Long getExpiresInMinutes();
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.diboot.shiro.service;
|
||||
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.shiro.entity.Permission;
|
||||
|
||||
/**
|
||||
* 许可授权相关Service
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
public interface PermissionService extends BaseService<Permission> {
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.diboot.shiro.service;
|
||||
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.shiro.entity.RolePermission;
|
||||
|
||||
/**
|
||||
* 角色授权相关Service
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
public interface RolePermissionService extends BaseService<RolePermission> {
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.diboot.shiro.service;
|
||||
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.shiro.entity.Role;
|
||||
import com.diboot.shiro.vo.RoleVO;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 角色相关Service
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
public interface RoleService extends BaseService<Role> {
|
||||
|
||||
/***
|
||||
* 根据用户类型和用户id获取角色关联权限列表
|
||||
* @param userType
|
||||
* @param userId
|
||||
* @return
|
||||
*/
|
||||
List<RoleVO> getRelatedRoleAndPermissionListByUser(String userType, Long userId);
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.diboot.shiro.service;
|
||||
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.shiro.entity.SysUser;
|
||||
|
||||
/**
|
||||
* 用户相关Service
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
public interface SysUserService extends BaseService<SysUser> {
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.diboot.shiro.service;
|
||||
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.shiro.entity.UserRole;
|
||||
|
||||
/**
|
||||
* 用户角色Service
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
public interface UserRoleService extends BaseService<UserRole> {
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package com.diboot.shiro.service.impl;
|
||||
|
||||
import com.diboot.core.service.impl.BaseServiceImpl;
|
||||
import com.diboot.shiro.entity.Permission;
|
||||
import com.diboot.shiro.mapper.PermissionMapper;
|
||||
import com.diboot.shiro.service.PermissionService;
|
||||
import com.diboot.shiro.service.SysUserService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 许可授权相关Service
|
||||
* @author Mazhicheng
|
||||
* @version 2018/12/23
|
||||
* Copyright © www.dibo.ltd
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class PermissionServiceImpl extends BaseServiceImpl<PermissionMapper, Permission> implements PermissionService {
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.diboot.shiro.service.impl;
|
||||
|
||||
import com.diboot.core.service.impl.BaseServiceImpl;
|
||||
import com.diboot.shiro.entity.RolePermission;
|
||||
import com.diboot.shiro.mapper.RolePermissionMapper;
|
||||
import com.diboot.shiro.service.RolePermissionService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 角色授权相关Service
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class RolePermissionServiceImpl extends BaseServiceImpl<RolePermissionMapper, RolePermission> implements RolePermissionService {
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package com.diboot.shiro.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.diboot.core.service.impl.BaseServiceImpl;
|
||||
import com.diboot.core.util.V;
|
||||
import com.diboot.shiro.entity.Permission;
|
||||
import com.diboot.shiro.entity.Role;
|
||||
import com.diboot.shiro.entity.UserRole;
|
||||
import com.diboot.shiro.mapper.RoleMapper;
|
||||
import com.diboot.shiro.service.RoleService;
|
||||
import com.diboot.shiro.service.UserRoleService;
|
||||
import com.diboot.shiro.vo.RoleVO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 角色相关Service
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class RoleServiceImpl extends BaseServiceImpl<RoleMapper, Role> implements RoleService {
|
||||
|
||||
@Autowired
|
||||
private UserRoleService userRoleService;
|
||||
|
||||
@Override
|
||||
public List<RoleVO> getRelatedRoleAndPermissionListByUser(String userType, Long userId) {
|
||||
// 根据用户类型与用户id获取roleList
|
||||
QueryWrapper<UserRole> query = new QueryWrapper<>();
|
||||
query.lambda()
|
||||
.eq(UserRole::getUserType, userType)
|
||||
.eq(UserRole::getUserId, userId);
|
||||
List<UserRole> userRoleList = userRoleService.getEntityList(query);
|
||||
if (V.isEmpty(userRoleList)){
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<Long> roleIdList = userRoleList.stream()
|
||||
.map(UserRole::getRoleId)
|
||||
.collect(Collectors.toList());
|
||||
if (V.isEmpty(roleIdList)){
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 获取角色列表,并使用VO自动多对多关联permission
|
||||
QueryWrapper<Role> roleQuery = new QueryWrapper<>();
|
||||
roleQuery
|
||||
.lambda()
|
||||
.in(Role::getId, roleIdList);
|
||||
List<RoleVO> roleVOList = this.getViewObjectList(roleQuery, null, RoleVO.class);
|
||||
return roleVOList;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.diboot.shiro.service.impl;
|
||||
|
||||
import com.diboot.core.service.impl.BaseServiceImpl;
|
||||
import com.diboot.shiro.entity.SysUser;
|
||||
import com.diboot.shiro.mapper.SysUserMapper;
|
||||
import com.diboot.shiro.service.SysUserService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 用户相关Service
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class SysUserServiceImpl extends BaseServiceImpl<SysUserMapper, SysUser> implements SysUserService {
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package com.diboot.shiro.service.impl;
|
||||
|
||||
import com.diboot.core.service.impl.BaseServiceImpl;
|
||||
import com.diboot.shiro.entity.UserRole;
|
||||
import com.diboot.shiro.mapper.UserRoleMapper;
|
||||
import com.diboot.shiro.service.PermissionService;
|
||||
import com.diboot.shiro.service.UserRoleService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 用户角色相关Service
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class UserRoleServiceImpl extends BaseServiceImpl<UserRoleMapper, UserRole> implements UserRoleService {
|
||||
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package com.diboot.shiro.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import com.diboot.core.util.V;
|
||||
import com.diboot.shiro.jwt.BaseJwtAuthenticationToken;
|
||||
import com.diboot.shiro.config.AuthType;
|
||||
import com.diboot.shiro.entity.SysUser;
|
||||
import com.diboot.shiro.service.AuthWayService;
|
||||
import com.diboot.shiro.service.SysUserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/***
|
||||
* 用户名密码认证实现
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
@Service
|
||||
public class UsernamePasswordAuthWayServiceImpl implements AuthWayService {
|
||||
|
||||
@Autowired
|
||||
private SysUserService sysUserService;
|
||||
|
||||
private AuthType authType = AuthType.USERNAME_PASSWORD;
|
||||
|
||||
private BaseJwtAuthenticationToken token;
|
||||
|
||||
@Override
|
||||
public AuthType authType() {
|
||||
return authType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initByToken(BaseJwtAuthenticationToken token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseEntity getUser() {
|
||||
QueryWrapper<SysUser> query = new QueryWrapper();
|
||||
query.lambda()
|
||||
.eq(SysUser::getUsername, token.getAccount());
|
||||
List<SysUser> userList = sysUserService.getEntityList(query);
|
||||
if (V.isEmpty(userList)){
|
||||
return null;
|
||||
}
|
||||
return userList.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requirePassword() {
|
||||
return authType.isRequirePassword();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPasswordMatch() {
|
||||
String password = token.getPassword();
|
||||
|
||||
// 构建查询条件
|
||||
QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.lambda()
|
||||
.eq(SysUser::getUsername, token.getAccount())
|
||||
.eq(SysUser::getPassword, password);
|
||||
|
||||
// 获取单条用户记录
|
||||
List<SysUser> userList = sysUserService.getEntityList(queryWrapper);
|
||||
|
||||
return V.notEmpty(userList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPreliminaryVerified() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getExpiresInMinutes() {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package com.diboot.shiro.util;
|
||||
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class AuthHelper {
|
||||
private static final Logger logger = LoggerFactory.getLogger(AuthHelper.class);
|
||||
|
||||
/**
|
||||
* 得到当前登录的用户名
|
||||
* @return
|
||||
*/
|
||||
public static <T extends BaseEntity>T getCurrentUser(){
|
||||
try{
|
||||
Subject subject = SecurityUtils.getSubject();
|
||||
if(subject != null && subject.isAuthenticated()){
|
||||
return (T)subject.getPrincipal();
|
||||
}
|
||||
}
|
||||
catch (Exception e){
|
||||
logger.warn("获取用户信息异常", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到当前登录的用户id
|
||||
* @return
|
||||
*/
|
||||
public static Long getCurrentUserId(){
|
||||
BaseEntity user = getCurrentUser();
|
||||
if(user != null){
|
||||
return (Long)user.getId();
|
||||
}
|
||||
if(logger.isDebugEnabled()){
|
||||
logger.warn("无法获取当前用户Id!");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
package com.diboot.shiro.util;
|
||||
|
||||
import com.diboot.core.config.BaseConfig;
|
||||
import com.diboot.core.util.V;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Token相关操作类
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
public class JwtHelper {
|
||||
private static final Logger logger = LoggerFactory.getLogger(JwtHelper.class);
|
||||
|
||||
private static final String ISSUER = V.notEmpty(BaseConfig.getProperty("diboot.shiro.jwt.issuer")) ? BaseConfig.getProperty("diboot.shiro.jwt.issuer") : "diboot.com";
|
||||
private static final String AUTH_HEADER = V.notEmpty(BaseConfig.getProperty("diboot.shiro.jwt.auth.header.key")) ? BaseConfig.getProperty("diboot.shiro.jwt.auth.header.key") : "authtoken";
|
||||
private static final String TOKEN_PREFIX = V.notEmpty(BaseConfig.getProperty("diboot.shiro.jwt.token.prefix")) ? BaseConfig.getProperty("diboot.shiro.jwt.token.prefix") : "Bearer ";
|
||||
public static final String SIGN_KEY = V.notEmpty(BaseConfig.getProperty("diboot.shiro.jwt.signkey"))? BaseConfig.getProperty("diboot.shiro.jwt.signkey") : "Dibo2016Mazc";
|
||||
|
||||
// 默认过期时间 2小时
|
||||
public static final int EXPIRES_IN_MINUTES = V.notEmpty(BaseConfig.getProperty("diboot.shiro.jwt.token.expires.hours")) ? Integer.valueOf(BaseConfig.getProperty("diboot.shiro.jwt.token.expires.hours")) * 60 : 2 * 60;
|
||||
private static final SignatureAlgorithm SIGNATURE_ALGORITHM = SignatureAlgorithm.HS256;
|
||||
|
||||
/***
|
||||
* 从token中获取用户名
|
||||
* @param token
|
||||
* @return
|
||||
*/
|
||||
public static String getAccountFromToken(String token){
|
||||
return getAccountFromToken(token, SIGN_KEY);
|
||||
}
|
||||
|
||||
/***
|
||||
* 从token中获取用户名
|
||||
* @param token
|
||||
* @return
|
||||
*/
|
||||
public static String getAccountFromToken(String token, String key){
|
||||
String username;
|
||||
try {
|
||||
Claims claims = getClaimsFromToken(token, key);
|
||||
// 校验过期时间
|
||||
if(claims.getExpiration().getTime() >= System.currentTimeMillis()){
|
||||
username = claims.getSubject();
|
||||
logger.debug("token有效,username=" + username);
|
||||
}
|
||||
else{
|
||||
logger.warn("token已过期:" + token);
|
||||
username = null;
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.warn("解析token异常,无效的token:" + token);
|
||||
username = null;
|
||||
}
|
||||
return username;
|
||||
}
|
||||
|
||||
/***
|
||||
* 从请求头中获取客户端发来的token
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public static String getRequestToken(HttpServletRequest request) {
|
||||
String authHeader = request.getHeader(AUTH_HEADER);
|
||||
if(authHeader != null){
|
||||
if(authHeader.startsWith(TOKEN_PREFIX)){
|
||||
return authHeader.substring(7);
|
||||
}
|
||||
return authHeader.trim();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/***
|
||||
* 请求头的token是否处于有效期限内
|
||||
*/
|
||||
public static boolean isRequestTokenEffective(HttpServletRequest request){
|
||||
String authToken = getRequestToken(request);
|
||||
if(V.notEmpty(authToken)){
|
||||
String account = getAccountFromToken(authToken);
|
||||
return V.notEmpty(account);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/***
|
||||
* 生成Token
|
||||
* @param username
|
||||
* @param signKey
|
||||
* @return
|
||||
*/
|
||||
public static String generateToken(String username, String signKey) {
|
||||
return generateToken(username, ISSUER, SIGNATURE_ALGORITHM, signKey, EXPIRES_IN_MINUTES);
|
||||
}
|
||||
|
||||
/***
|
||||
* 生成Token
|
||||
* @param username
|
||||
* @param signKey
|
||||
* @param expiresInMinutes
|
||||
* @return
|
||||
*/
|
||||
public static String generateToken(String username, String signKey, long expiresInMinutes) {
|
||||
return generateToken(username, ISSUER, SIGNATURE_ALGORITHM, signKey, expiresInMinutes);
|
||||
}
|
||||
|
||||
/***
|
||||
* 生成token
|
||||
* @param user
|
||||
* @param issuer
|
||||
* @param signAlgorithm
|
||||
* @param signKey
|
||||
* @param expiresInMinutes
|
||||
* @return
|
||||
*/
|
||||
public static String generateToken(String user, String issuer, SignatureAlgorithm signAlgorithm, String signKey, long expiresInMinutes) {
|
||||
Date currentTime = generateCurrentDate();
|
||||
Date expiration = generateExpirationDate(currentTime, expiresInMinutes);
|
||||
String jwsToken = Jwts.builder()
|
||||
.setIssuer(issuer)
|
||||
.setSubject(user)
|
||||
.setIssuedAt(currentTime)
|
||||
.setExpiration(expiration)
|
||||
.signWith(signAlgorithm, signKey)
|
||||
.compact();
|
||||
return jwsToken;
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取Token
|
||||
* @param token
|
||||
* @return
|
||||
*/
|
||||
public static Claims getClaimsFromToken(String token, String key) {
|
||||
Claims claims;
|
||||
try {
|
||||
claims = Jwts.parser().setSigningKey(key)
|
||||
.parseClaimsJws(token).getBody();
|
||||
}
|
||||
catch (Exception e) {
|
||||
claims = null;
|
||||
}
|
||||
return claims;
|
||||
}
|
||||
|
||||
/***
|
||||
* 校验Token
|
||||
* @param authToken
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public static boolean isValidToken(String authToken, String key, String expectedUsername) {
|
||||
try {
|
||||
final Claims claims = getClaimsFromToken(authToken, key);
|
||||
if(claims != null){
|
||||
String authUsername = claims.getSubject();
|
||||
// 校验用户名
|
||||
if(authUsername != null && authUsername.equals(expectedUsername)){
|
||||
// 校验过期时间
|
||||
return claims.getExpiration().getTime() >= System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.warn("校验token异常", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/***
|
||||
* 生成当前时间戳
|
||||
* @return
|
||||
*/
|
||||
public static Date generateCurrentDate() {
|
||||
return new Date(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/***
|
||||
* 生成过期时间戳
|
||||
* @return
|
||||
*/
|
||||
public static Date generateExpirationDate(Date currentTime, long expiresInMinutes) {
|
||||
return new Date(currentTime.getTime() + (expiresInMinutes*60000));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.diboot.shiro.vo;
|
||||
|
||||
import com.diboot.core.binding.annotation.BindEntityList;
|
||||
import com.diboot.shiro.entity.Permission;
|
||||
import com.diboot.shiro.entity.Role;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
@Data
|
||||
public class PermissionVO extends Permission {
|
||||
|
||||
private static final long serialVersionUID = 860775286174387052L;
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.diboot.shiro.vo;
|
||||
|
||||
import com.diboot.core.binding.annotation.BindEntityList;
|
||||
import com.diboot.shiro.entity.Permission;
|
||||
import com.diboot.shiro.entity.Role;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
@Data
|
||||
public class RoleVO extends Role {
|
||||
|
||||
private static final long serialVersionUID = 860775286174387052L;
|
||||
|
||||
// 支持通过中间表的多-多Entity实体关联
|
||||
@BindEntityList(entity = Permission.class, condition="this.id=role_permission.role_id AND role_permission.permission_id=id")
|
||||
private List<Permission> permissionList;
|
||||
|
||||
}
|
Binary file not shown.
|
@ -1,5 +0,0 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.0-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
|
@ -10,4 +10,6 @@
|
|||
rootProject.name = 'diboot-v2'
|
||||
include 'diboot-core'
|
||||
include 'diboot-example'
|
||||
include 'diboot-shiro'
|
||||
include 'diboot-docs'
|
||||
|
||||
|
|
Loading…
Reference in New Issue