build: first commit

This commit is contained in:
fit2cloud-chenyw 2021-02-18 17:30:29 +08:00
parent b03f895ec5
commit 92b36f38d6
65 changed files with 2543 additions and 0 deletions

4
.gitignore vendored
View File

@ -21,3 +21,7 @@
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
/.idea/
target/
*.iml
.DS_Store

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>fit2cloud-commons</artifactId>
<groupId>com.fit2cloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>fit2cloud-common-auth</artifactId>
<dependencies>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>${jwt.version}</version>
</dependency>
<dependency>
<groupId>com.fit2cloud</groupId>
<artifactId>fit2cloud-common-db</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>${ehcache.version}</version>
</dependency>
<!--下面是数据层mybatis配置-->
</dependencies>
</project>

View File

@ -0,0 +1,59 @@
package com.fit2cloud.commons.auth.api;
import cn.hutool.core.util.StrUtil;
import com.fit2cloud.commons.auth.bean.LoginDto;
import com.fit2cloud.commons.auth.bean.UserBean;
import com.fit2cloud.commons.auth.bean.UserInfo;
import com.fit2cloud.commons.auth.service.UserService;
import com.fit2cloud.commons.auth.util.JWTUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
public class UserApi {
@Autowired
private UserService userService;
@PostMapping("/login")
public Map<String, Object> login(@RequestBody LoginDto loginDto){
String username = loginDto.getUsername();
String password = loginDto.getPassword();
String realPwd = userService.getPassword(username);
if (StrUtil.isEmpty(realPwd)){
throw new RuntimeException("没有该用户!");
}
if (!StrUtil.equals(realPwd, password)){
throw new RuntimeException("密码错误!");
}
Map<String,Object> result = new HashMap<>();
result.put("token", JWTUtil.sign(username, password));
return result;
}
@GetMapping("/info")
public UserInfo getUserInfo(){
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
String token = request.getHeader("Authorization");
String username = JWTUtil.getUsername(token);
UserBean user = userService.getUser(username);
String[] split = user.getRole().split(",");
List<String> strings = Arrays.asList(split);
UserInfo info = UserInfo.builder().name(user.getUsername()).roles(strings).avatar("http://fit2cloud.com").introduction(user.getUsername()).build();
return info;
}
@PostMapping("/logout")
public String logout(){
return "success";
}
}

View File

@ -0,0 +1,19 @@
package com.fit2cloud.commons.auth.bean;
import com.fit2cloud.commons.auth.entity.Permission;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ExtPermissionBean extends Permission {
private String url;
public PermissionKey getKey(){
return PermissionKey.builder().resourceId(getResourceId()).url(url).build();
}
}

View File

@ -0,0 +1,20 @@
package com.fit2cloud.commons.auth.bean;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class LoginDto implements Serializable {
private String username;
private String password;
}

View File

@ -0,0 +1,41 @@
package com.fit2cloud.commons.auth.bean;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 作为HashMap key
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PermissionKey {
private String resourceId;
private String url;
/**
* 重写equals方法必须重写hashCode方法
* @param anObject
* @return
*/
public boolean equals(Object anObject) {
if (this == anObject)return true;
if (anObject instanceof PermissionKey){
PermissionKey current = (PermissionKey) anObject;
if (current == null || current.resourceId == null)return false;
return current.resourceId.equals(this.resourceId);
}
return false;
}
public int hashCode() {
return resourceId.hashCode();
}
}

View File

@ -0,0 +1,22 @@
package com.fit2cloud.commons.auth.bean;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserBean {
private String username;
private String password;
private String role;
private String permission;
}

View File

@ -0,0 +1,26 @@
package com.fit2cloud.commons.auth.bean;
import com.fit2cloud.commons.auth.entity.User;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UserInfo implements Serializable {
private List<String> roles;
private String introduction;
private String name;
private String avatar;
}

View File

@ -0,0 +1,32 @@
package com.fit2cloud.commons.auth.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import java.util.Collections;
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
//1,允许任何来源
corsConfiguration.setAllowedOriginPatterns(Collections.singletonList("*"));
//2,允许任何请求头
corsConfiguration.addAllowedHeader(CorsConfiguration.ALL);
//3,允许任何方法
corsConfiguration.addAllowedMethod(CorsConfiguration.ALL);
//4,允许凭证
corsConfiguration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(source);
}
}

View File

@ -0,0 +1,77 @@
package com.fit2cloud.commons.auth.config;
import com.fit2cloud.commons.auth.bean.UserBean;
import com.fit2cloud.commons.auth.service.UserService;
import com.fit2cloud.commons.auth.util.JWTUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
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 org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
@Component
public class F2cRealm extends AuthorizingRealm {
private static final Logger LOGGER = LogManager.getLogger(F2cRealm.class);
@Autowired
private UserService userService;
/**
* 大坑必须重写此方法不然Shiro会报错
*/
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof JWTToken;
}
/**
* 只有当需要检测用户权限的时候才会调用此方法例如checkRole,checkPermission之类的
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = JWTUtil.getUsername(principals.toString());
UserBean user = userService.getUser(username);
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
Set<String> role = new HashSet<>(Arrays.asList(user.getRole().split(",")));
simpleAuthorizationInfo.addRoles(role);
Set<String> permission = new HashSet<>(Arrays.asList(user.getPermission().split(",")));
simpleAuthorizationInfo.addStringPermissions(permission);
return simpleAuthorizationInfo;
}
/**
* 默认使用此方法进行用户名正确与否验证错误抛出异常即可
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
String token = (String) auth.getCredentials();
// 解密获得username用于和数据库进行对比
String username = JWTUtil.getUsername(token);
if (username == null) {
throw new AuthenticationException("token invalid");
}
UserBean userBean = userService.getUser(username);
if (userBean == null) {
throw new AuthenticationException("User didn't existed!");
}
if (! JWTUtil.verify(token, username, userBean.getPassword())) {
throw new AuthenticationException("Username or password error");
}
return new SimpleAuthenticationInfo(token, token, "my_realm");
}
}

View File

@ -0,0 +1,22 @@
package com.fit2cloud.commons.auth.config;
import org.apache.shiro.authc.AuthenticationToken;
public class JWTToken implements AuthenticationToken {
private String token;
public JWTToken(String token) {
this.token = token;
}
@Override
public Object getPrincipal() {
return token;
}
@Override
public Object getCredentials() {
return token;
}
}

View File

@ -0,0 +1,83 @@
package com.fit2cloud.commons.auth.config;
import com.fit2cloud.commons.auth.filter.F2CLogoutFilter;
import com.fit2cloud.commons.auth.filter.F2CPermissionsFilter;
import com.fit2cloud.commons.auth.filter.F2CRolesFilter;
import com.fit2cloud.commons.auth.filter.JWTFilter;
import com.fit2cloud.commons.auth.service.ShiroService;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
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.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
@Bean("securityManager")
public DefaultWebSecurityManager getManager(F2cRealm f2cRealm) {
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
// 使用自己的realm
manager.setRealm(f2cRealm);
/*
* 关闭shiro自带的session详情见文档
* http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29
*/
DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
manager.setSubjectDAO(subjectDAO);
return manager;
}
@Bean("shiroFilter")
public ShiroFilterFactoryBean factory(DefaultWebSecurityManager securityManager, ShiroService shiroService) {
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
// 添加自己的过滤器并且取名为jwt
Map<String, Filter> filterMap = new LinkedHashMap<>();
filterMap.put("f2cPerms", new F2CPermissionsFilter());
//filterMap.put("f2cRoles", new F2CRolesFilter());
filterMap.put("jwt", new JWTFilter());
filterMap.put("logout", new F2CLogoutFilter());
factoryBean.setFilters(filterMap);
factoryBean.setSecurityManager(securityManager);
factoryBean.setUnauthorizedUrl("/permissionMiss");
factoryBean.setFilterChainDefinitionMap(shiroService.loadFilterChainDefinitionMap());
return factoryBean;
}
/**
* 下面的代码是添加注解支持
*/
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
}

View File

@ -0,0 +1,31 @@
package com.fit2cloud.commons.auth.dao;
import com.fit2cloud.commons.auth.bean.ExtPermissionBean;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface ExtUserMapper {
@Select("select password from user where user_id = #{userId,jdbcType=VARCHAR} ")
String getPassword(String userId);
@Select("select role_id from role_user where user_id = #{userId,jdbcType=VARCHAR} ")
List<String> getRole(String userId);
@Select({
"select resource_id from permission p " ,
"left join role_user ru on p.relation_id = ru.role_id " ,
"where type = 'role' and ru.user_id = #{userId,jdbcType=VARCHAR} "
})
List<String> getPermission(String userId);
@Select({
"select p.*,r.url ",
"from permission p left join resource r on p.resource_id = r.id"
})
List<ExtPermissionBean> getPermissions();
}

View File

@ -0,0 +1,44 @@
package com.fit2cloud.commons.auth.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableField;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
*
* </p>
*
* @author cyw
* @since 2021-02-03
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("org_user")
public class OrgUser implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId("id")
private String id;
/**
* 部门ID
*/
@TableField("org_id")
private String orgId;
/**
* 用户ID
*/
@TableField("user_id")
private String userId;
}

View File

@ -0,0 +1,62 @@
package com.fit2cloud.commons.auth.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableField;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
*
* </p>
*
* @author cyw
* @since 2021-02-03
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("organization")
public class Organization implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId("id")
private String id;
/**
* 部门名称
*/
@TableField("name")
private String name;
/**
* 描述
*/
@TableField("description")
private String description;
/**
* 上级部门ID
*/
@TableField("pid")
private Integer pid;
/**
* 部门级别
*/
@TableField("level")
private Integer level;
/**
* 创建时间
*/
@TableField("create_time")
private Long createTime;
}

View File

@ -0,0 +1,50 @@
package com.fit2cloud.commons.auth.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableField;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
*
* </p>
*
* @author cyw
* @since 2021-02-03
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("permission")
public class Permission implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId("id")
private String id;
/**
* 类型
*/
@TableField("type")
private String type;
/**
* 关联ID
*/
@TableField("relation_id")
private String relationId;
/**
* 资源ID
*/
@TableField("resource_id")
private String resourceId;
}

View File

@ -0,0 +1,62 @@
package com.fit2cloud.commons.auth.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableField;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
*
* </p>
*
* @author cyw
* @since 2021-02-03
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("resource")
public class Resource implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId("id")
private String id;
/**
* 资源名称
*/
@TableField("name")
private String name;
/**
* 资源描述
*/
@TableField("desc")
private String desc;
/**
* 资源类型
*/
@TableField("type")
private String type;
/**
* 资源地址
*/
@TableField("url")
private String url;
/**
* 创建时间
*/
@TableField("create_time")
private Long createTime;
}

View File

@ -0,0 +1,50 @@
package com.fit2cloud.commons.auth.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableField;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
*
* </p>
*
* @author cyw
* @since 2021-02-03
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("role")
public class Role implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 角色ID
*/
@TableId("id")
private String id;
/**
* 角色名称
*/
@TableField("name")
private String name;
/**
* 角色类型
*/
@TableField("type")
private String type;
/**
* 描述
*/
@TableField("description")
private String description;
}

View File

@ -0,0 +1,44 @@
package com.fit2cloud.commons.auth.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableField;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
*
* </p>
*
* @author cyw
* @since 2021-02-03
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("role_user")
public class RoleUser implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId("id")
private String id;
/**
* 角色ID
*/
@TableField("role_id")
private String roleId;
/**
* 用户ID
*/
@TableField("user_id")
private String userId;
}

View File

@ -0,0 +1,68 @@
package com.fit2cloud.commons.auth.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableField;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
*
* </p>
*
* @author cyw
* @since 2021-02-03
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("user")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId("user_id")
private String userId;
/**
* 姓名
*/
@TableField("user_name")
private String userName;
/**
* 密码
*/
@TableField("password")
private String password;
/**
* 是否有效
*/
@TableField("valid")
private Boolean valid;
/**
* 电话号码
*/
@TableField("phone_number")
private Integer phoneNumber;
/**
* 邮箱
*/
@TableField("email")
private String email;
/**
* 创建时间
*/
@TableField("create_time")
private Long createTime;
}

View File

@ -0,0 +1,27 @@
package com.fit2cloud.commons.auth.filter;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.LogoutFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class F2CLogoutFilter extends LogoutFilter {
private static final Logger logger = LoggerFactory.getLogger(F2CLogoutFilter.class);
@Override
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
Subject subject = getSubject(request, response);
try {
subject.logout();
} catch (Exception ex) {
logger.error("退出登录错误",ex);
}
return true;
}
}

View File

@ -0,0 +1,30 @@
package com.fit2cloud.commons.auth.filter;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
public class F2CPermissionsFilter extends PermissionsAuthorizationFilter {
@Override
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
Subject subject = getSubject(request, response);
String[] perms = (String[]) mappedValue;
if (perms != null && perms.length > 0) {
for (String str : perms) {
// 判断访问的用户是否拥有mappedValue权限
if (subject.isPermitted(str)) {
return true;
}
}
return false;
}
return true;
}
}

View File

@ -0,0 +1,25 @@
package com.fit2cloud.commons.auth.filter;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class F2CRolesFilter extends AuthorizationFilter {
@Override
protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception {
Subject subject = getSubject(servletRequest, servletResponse);
String[] rolesArray = (String[]) o;
// 没有角色限制有权限访问
if (rolesArray == null || rolesArray.length == 0) {
return true;
}
for (int i = 0; i < rolesArray.length; i++) {
//若当前用户是rolesArray中的任何一个则有权限访问
if (subject.hasRole(rolesArray[i])) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,121 @@
package com.fit2cloud.commons.auth.filter;
import com.fit2cloud.commons.auth.config.JWTToken;
import com.fit2cloud.commons.auth.util.JWTUtil;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class JWTFilter extends BasicHttpAuthenticationFilter {
private Logger LOGGER = LoggerFactory.getLogger(this.getClass());
/**
* 判断用户是否想要登入
* 检测header里面是否包含Authorization字段即可
*/
@Override
protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
HttpServletRequest req = (HttpServletRequest) request;
String authorization = req.getHeader("Authorization");
return authorization != null;
}
/**
*
*/
@Override
protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String authorization = httpServletRequest.getHeader("Authorization");
if (JWTUtil.needRefresh(authorization)){
authorization = refreshToken(request, response);
}
JWTToken token = new JWTToken(authorization);
Subject subject = getSubject(request, response);
// 提交给realm进行登入如果错误他会抛出异常并被捕获
subject.login(token);
return true;
}
/**
*/
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
if (isLoginAttempt(request, response)) {
try {
boolean loginSuccess = executeLogin(request, response);
return loginSuccess;
} catch (Exception e) {
response401(request, response);
}
}
return false;
}
private String refreshToken(ServletRequest request, ServletResponse response) {
// 获取AccessToken(Shiro中getAuthzHeader方法已经实现)
String token = this.getAuthzHeader(request);
// 获取当前Token的帐号信息
String username = JWTUtil.getUsername(token);
String password = JWTUtil.getPassword(username);
try {
String newToken = JWTUtil.sign(username, password);
JWTToken jwtToken = new JWTToken(newToken);
this.getSubject(request, response).login(jwtToken);
// 设置响应的Header头新Token
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.addHeader("Access-Control-Expose-Headers", "Authorization");
httpServletResponse.setHeader("Authorization", newToken);
return newToken;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
/**
* 对跨域提供支持
*/
@Override
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
// 跨域时会首先发送一个option请求这里我们给option请求直接返回正常状态
if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
httpServletResponse.setStatus(HttpStatus.OK.value());
return false;
}
return super.preHandle(request, response);
}
/**
* 将非法请求跳转到 /401
*/
private void response401(ServletRequest req, ServletResponse resp) {
try {
HttpServletResponse httpServletResponse = (HttpServletResponse) resp;
httpServletResponse.sendRedirect("/401");
} catch (IOException e) {
LOGGER.error(e.getMessage());
}
}
}

View File

@ -0,0 +1,52 @@
package com.fit2cloud.commons.auth.filter;
import cn.hutool.core.util.StrUtil;
import org.apache.commons.text.StringEscapeUtils;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
@Component
@WebFilter
public class XssFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
XssHttpServletRequestWrapper xssHttpServletRequestWrapper = new XssHttpServletRequestWrapper((HttpServletRequest) request);
filterChain.doFilter(xssHttpServletRequestWrapper, response);
}
@Override
public void destroy() {
}
class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
private HttpServletRequest request;
public XssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
this.request = request;
}
@Override
public String getParameter(String name) {
String oldValue = super.getParameter(name);
if(StrUtil.isEmpty(oldValue)){
return oldValue;
}
String newValue = StringEscapeUtils.escapeHtml4(oldValue);
return newValue;
}
}
}

View File

@ -0,0 +1,19 @@
package com.fit2cloud.commons.auth.mapper;
import com.fit2cloud.commons.auth.entity.OrgUser;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author cyw
* @since 2021-02-03
*/
@Mapper
public interface OrgUserMapper extends BaseMapper<OrgUser> {
}

View File

@ -0,0 +1,19 @@
package com.fit2cloud.commons.auth.mapper;
import com.fit2cloud.commons.auth.entity.Organization;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author cyw
* @since 2021-02-03
*/
@Mapper
public interface OrganizationMapper extends BaseMapper<Organization> {
}

View File

@ -0,0 +1,19 @@
package com.fit2cloud.commons.auth.mapper;
import com.fit2cloud.commons.auth.entity.Permission;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author cyw
* @since 2021-02-03
*/
@Mapper
public interface PermissionMapper extends BaseMapper<Permission> {
}

View File

@ -0,0 +1,19 @@
package com.fit2cloud.commons.auth.mapper;
import com.fit2cloud.commons.auth.entity.Resource;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author cyw
* @since 2021-02-03
*/
@Mapper
public interface ResourceMapper extends BaseMapper<Resource> {
}

View File

@ -0,0 +1,19 @@
package com.fit2cloud.commons.auth.mapper;
import com.fit2cloud.commons.auth.entity.Role;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author cyw
* @since 2021-02-03
*/
@Mapper
public interface RoleMapper extends BaseMapper<Role> {
}

View File

@ -0,0 +1,19 @@
package com.fit2cloud.commons.auth.mapper;
import com.fit2cloud.commons.auth.entity.RoleUser;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author cyw
* @since 2021-02-03
*/
@Mapper
public interface RoleUserMapper extends BaseMapper<RoleUser> {
}

View File

@ -0,0 +1,19 @@
package com.fit2cloud.commons.auth.mapper;
import com.fit2cloud.commons.auth.entity.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author cyw
* @since 2021-02-03
*/
@Mapper
public interface UserMapper extends BaseMapper<User> {
}

View File

@ -0,0 +1,36 @@
package com.fit2cloud.commons.auth.service;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import java.util.Map;
public interface ShiroService {
/**
* 初始化权限 -> 拿全部权限
*
* @param :
* @return: java.util.Map<java.lang.String,java.lang.String>
*/
Map<String, String> loadFilterChainDefinitionMap();
/**
* 在对uri权限进行增删改操作时需要调用此方法进行动态刷新加载数据库中的uri权限
*
* @param shiroFilterFactoryBean
* @param roleId
* @param isRemoveSession:
* @return: void
*/
void updatePermission(ShiroFilterFactoryBean shiroFilterFactoryBean, Integer roleId, Boolean isRemoveSession);
/**
* shiro动态权限加载 -> 原理删除shiro缓存重新执行doGetAuthorizationInfo方法授权角色和权限
*
* @param roleId
* @param isRemoveSession:
* @return: void
*/
void updatePermissionByRoleId(Integer roleId, Boolean isRemoveSession);
}

View File

@ -0,0 +1,40 @@
package com.fit2cloud.commons.auth.service;
import cn.hutool.core.util.ObjectUtil;
import com.fit2cloud.commons.auth.bean.UserBean;
import com.fit2cloud.commons.auth.dao.ExtUserMapper;
import com.fit2cloud.commons.auth.entity.User;
import com.fit2cloud.commons.auth.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class UserService {
@Autowired(required = false)
private ExtUserMapper extUserMapper;
@Autowired(required = false)
private UserMapper userMapper;
public UserBean getUser(String username){
User user = userMapper.selectById(username);
if (ObjectUtil.isNull(user))return null;
String password = user.getPassword();
List<String> roles = extUserMapper.getRole(username);
String role = roles.stream().collect(Collectors.joining(","));
List<String> permissions = extUserMapper.getPermission(username);
String permission = permissions.stream().collect(Collectors.joining(","));
UserBean userBean = UserBean.builder().username(username).password(password).role(role).permission(permission).build();
return userBean;
}
public String getPassword(String username){
String password = extUserMapper.getPassword(username);
return password;
}
}

View File

@ -0,0 +1,83 @@
package com.fit2cloud.commons.auth.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fit2cloud.commons.auth.dao.ExtUserMapper;
import com.fit2cloud.commons.auth.entity.Permission;
import com.fit2cloud.commons.auth.service.ShiroService;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.LinkedHashMap;
import java.util.Map;
@Service
public class ShiroServiceImpl implements ShiroService {
@Autowired(required = false)
private ExtUserMapper extUserMapper;
@Override
public Map<String, String> loadFilterChainDefinitionMap() {
// 权限控制map
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
// 配置过滤:不会被拦截的链接 -> 放行 start ----------------------------------------------------------
// 放行Swagger2页面需要放行这些
filterChainDefinitionMap.put("/swagger-ui.html","anon");
filterChainDefinitionMap.put("/swagger/**","anon");
filterChainDefinitionMap.put("/webjars/**", "anon");
filterChainDefinitionMap.put("/swagger-resources/**","anon");
filterChainDefinitionMap.put("/v2/**","anon");
filterChainDefinitionMap.put("/static/**", "anon");
// 登陆
filterChainDefinitionMap.put("/login", "anon");
// 退出
//filterChainDefinitionMap.put("/logout", "anon");
// 放行未授权接口重定向使用
filterChainDefinitionMap.put("/unauth", "anon");
// token过期接口
filterChainDefinitionMap.put("/tokenExpired", "anon");
// 被挤下线
filterChainDefinitionMap.put("/downline", "anon");
// 放行 end ----------------------------------------------------------
filterChainDefinitionMap.put("/logout", "logout");
//List<Resource> resources = resourceMapper.selectList(null);
QueryWrapper<Permission> wrapper = new QueryWrapper<>();
wrapper.eq("type", "role");
/*List<ExtPermissionBean> extPermissionBeans = extUserMapper.getPermissions();
if (CollectionUtils.isNotEmpty(extPermissionBeans)){
Map<PermissionKey, List<ExtPermissionBean>> resourcePerMap = extPermissionBeans.stream().collect(Collectors.groupingBy(ExtPermissionBean::getKey));
resourcePerMap.entrySet().stream().forEach(entry -> {
PermissionKey permissionKey = entry.getKey();
String url = permissionKey.getUrl();
String resourceId = permissionKey.getResourceId();
//List<ExtPermissionBean> permissionList = entry.getValue();
//StringJoiner f2cRoles = new StringJoiner(",", "f2cRoles[", "]");
StringJoiner f2cPerms = new StringJoiner(",", "f2cPerms[", "]");
f2cPerms.add(resourceId);
*//*permissionList.forEach(per -> {
String roleId = per.getRelationId();
f2cRoles.add(roleId);
});*//*
filterChainDefinitionMap.put(url, "jwt," + f2cPerms);
});
}*/
filterChainDefinitionMap.put("/**", "jwt");
return filterChainDefinitionMap;
}
@Override
public void updatePermission(ShiroFilterFactoryBean shiroFilterFactoryBean, Integer roleId, Boolean isRemoveSession) {
}
@Override
public void updatePermissionByRoleId(Integer roleId, Boolean isRemoveSession) {
}
}

View File

@ -0,0 +1,55 @@
package com.fit2cloud.commons.auth.util;
import cn.hutool.core.util.ObjectUtil;
import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.context.annotation.Configuration;
/*@Configuration
public class CacheUtil {
private static CacheManager manager;
@Autowired
public void setManager(CacheManager manager) {
CacheUtil.manager = manager;
}
public static Object get(String cacheName, Object key) {
Cache cache = cache(cacheName);
if (ObjectUtil.isNull(cache))return null;
Element element = cache.get(key);
if (ObjectUtil.isNull(element))return null;
Object objectValue = element.getObjectValue();
return objectValue;
}
public static void put(String cacheName, Object key, Object value, Integer ttl, Integer tti) {
Element e = new Element(key, value);
//不设置则使用xml配置
if (ttl != null)
e.setTimeToLive(ttl);
if (tti != null)
e.setTimeToIdle(tti);
cache(cacheName).put(e);
}
public static boolean remove(String cacheName, Object key) {
return cache(cacheName).remove(key);
}
public static void removeAll(String cacheName) {
cache(cacheName).removeAll();
}
private static Cache cache(String cacheName) {
net.sf.ehcache.CacheManager cacheManager = ((EhCacheCacheManager) manager).getCacheManager();
if (!cacheManager.cacheExists(cacheName))
cacheManager.addCache(cacheName);
Cache cache = cacheManager.getCache(cacheName);
return cache;
}
}*/

View File

@ -0,0 +1,101 @@
package com.fit2cloud.commons.auth.util;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.fit2cloud.commons.auth.dao.ExtUserMapper;
import com.fit2cloud.commons.auth.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class JWTUtil {
// 过期时间5分钟
private static final long EXPIRE_TIME = 5*60*1000;
private static ExtUserMapper extUserMapper;
@Autowired
public void setExtUserMapper(ExtUserMapper extUserMapper) {
JWTUtil.extUserMapper = extUserMapper;
}
/**
* 校验token是否正确
* @param token 密钥
* @param secret 用户的密码
* @return 是否正确
*/
public static boolean verify(String token, String username, String secret) {
Algorithm algorithm = Algorithm.HMAC256(secret);
JWTVerifier verifier = JWT.require(algorithm)
.withClaim("username", username)
.build();
verifier.verify(token);
return true;
}
/**
* 获得token中的信息无需secret解密也能获得
* @return token中包含的用户名
*/
public static String getUsername(String token) {
try {
DecodedJWT jwt = JWT.decode(token);
return jwt.getClaim("username").asString();
} catch (JWTDecodeException e) {
return null;
}
}
public static String getPassword(String username){
String password = extUserMapper.getPassword(username);
return password;
}
public static boolean needRefresh(String token){
Date exp = JWTUtil.getExp(token);
return new Date().getTime() >= exp.getTime();
}
public static Date getExp(String token) {
try {
DecodedJWT jwt = JWT.decode(token);
return jwt.getClaim("exp").asDate();
} catch (JWTDecodeException e) {
return null;
}
}
/**
* 生成签名,5min后过期
* @param username 用户名
* @param secret 用户的密码
* @return 加密的token
*/
public static String sign(String username, String secret) {
try {
Date date = new Date(System.currentTimeMillis()+EXPIRE_TIME);
Algorithm algorithm = Algorithm.HMAC256(secret);
// 附带username信息
return JWT.create()
.withClaim("username", username)
.withClaim("exp", date)
.withExpiresAt(date)
.sign(algorithm);
} catch (Exception e) {
return null;
}
}
}

View File

@ -0,0 +1,2 @@
spring.cache.type=ehcache
spring.cache.ehcache.config=ehcache.xml

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<diskStore path="/opt/fit2cloud/ehcache/"/>
<!--默认缓存策略-->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
overflowToDisk="true"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
<!--缓存用户token-->
<cache name="token-cache"
maxElementsInMemory="10000"
eternal="true"
diskPersistent="true"
overflowToDisk="true"
memoryStoreEvictionPolicy="LRU"
/>
</ehcache>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>fit2cloud-commons</artifactId>
<groupId>com.fit2cloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>fit2cloud-common-base</artifactId>
</project>

View File

@ -0,0 +1,71 @@
package com.fit2cloud.commons.base;
import cn.hutool.core.util.StrUtil;
import com.fit2cloud.commons.base.result.ResultEntity;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.*;
import javax.annotation.Resource;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@RestController
public class Fit2cloudException extends ResultEntity implements ErrorController {
public static final org.slf4j.Logger Logger = LoggerFactory.getLogger(Fit2cloudException.class);
private static final String PATH = "/error";
@Resource
private ErrorAttributes errorAttributes;
@Override
public String getErrorPath() {
return PATH;
}
@RequestMapping(PATH)
public ResultEntity error(){
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes attributes = (ServletRequestAttributes) requestAttributes;
HttpServletRequest request = attributes.getRequest();
HttpServletResponse response = attributes.getResponse();
WebRequest webRequest = new ServletWebRequest(request);
ErrorAttributeOptions.Include[] values = ErrorAttributeOptions.Include.values();
List<ErrorAttributeOptions.Include> collect = Stream.of(values).collect(Collectors.toList());
ErrorAttributeOptions options = ErrorAttributeOptions.of(collect);
Map<String, Object> errorAttributeMap = this.errorAttributes.getErrorAttributes(webRequest, options);
Throwable t = errorAttributes.getError(webRequest);
Integer code = (Integer) errorAttributeMap.get("status");
response.setStatus(code);
String errorMessage = StrUtil.EMPTY;
if (t != null) {
if (Logger.isDebugEnabled()) {
Logger.error("Fail to proceed " + errorAttributeMap.get("path"), t);
}
errorMessage = t.getMessage();
}
if (StrUtil.isBlank(errorMessage)) {
if (code == 403) {
errorMessage = "Permission Denied.";
} else if (code == 404) {
String path = request.getServletPath();
if(Objects.nonNull(request.getAttribute(RequestDispatcher.ERROR_REQUEST_URI)) && StrUtil.isNotBlank(request.getAttribute(RequestDispatcher.ERROR_REQUEST_URI).toString())){
path = request.getAttribute(RequestDispatcher.ERROR_REQUEST_URI).toString();
}
errorMessage = path + " not found.";
} else {
errorMessage = "The server responds " + code + " but no detailed message.";
}
}
return error(errorMessage);
}
}

View File

@ -0,0 +1,38 @@
package com.fit2cloud.commons.base;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.fit2cloud.commons.base.result.ResultEntity;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@RestControllerAdvice({"com.fit2cloud", "springfox.documentation.swagger2.web"})
public class Fit2cloudResult extends ResultEntity implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter methodParameter, Class converterType) {
return MappingJackson2HttpMessageConverter.class.isAssignableFrom(converterType) || StringHttpMessageConverter.class.isAssignableFrom(converterType);
}
@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class converterType, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
String path = serverHttpRequest.getURI().getPath();
if (StrUtil.equalsIgnoreCase(path, "/v2/api-docs")) {
return o;
}
if (!(o instanceof ResultEntity)) {
if (o instanceof String){
return JSONUtil.toJsonStr(success(o));
}
return success(o);
}
return o;
}
}

View File

@ -0,0 +1,13 @@
package com.fit2cloud.commons.base.api;
import com.fit2cloud.commons.base.result.ResultEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class PermissionErrorApi extends ResultEntity {
@GetMapping("/permissionMiss")
public ResultEntity error(){
return permission();
}
}

View File

@ -0,0 +1,14 @@
package com.fit2cloud.commons.base.api;
import com.fit2cloud.commons.base.result.ResultEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TokenExpApi extends ResultEntity {
@GetMapping("/tokenExp")
public ResultEntity tokenExp(){
return tokenExp();
}
}

View File

@ -0,0 +1,40 @@
package com.fit2cloud.commons.base.result;
import lombok.Data;
public enum ResultCode {
OK(null, 20000),TOKENIll("Illegal token", 50008),
RELOG("Other clients logged in", 50012),TOKENEXP("Token expired", 50014),NOPERMISSION("No permission!", 50016);
private String message;
private int value;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
ResultCode() {
}
ResultCode(String message, int value) {
this.message = message;
this.value = value;
}
}

View File

@ -0,0 +1,58 @@
package com.fit2cloud.commons.base.result;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ResultEntity implements Serializable {
private String message;
private boolean success;
private int code;
private Object data;
public ResultEntity success(){
this.code = ResultCode.OK.getValue();
this.success = true;
return this;
}
public ResultEntity success(Object o){
this.code = ResultCode.OK.getValue();
this.success = true;
this.data = o;
return this;
}
public ResultEntity error(){
this.code = 500;
this.success = false;
return this;
}
public ResultEntity error(String msg){
this.code = 500;
this.success = false;
this.message = msg;
return this;
}
public ResultEntity permission(){
this.code = ResultCode.NOPERMISSION.getValue();
this.success = false;
this.message = ResultCode.NOPERMISSION.getMessage();
return this;
}
public ResultEntity tokenExp(){
this.code = ResultCode.TOKENEXP.getValue();
this.success = false;
this.message = ResultCode.TOKENEXP.getMessage();
return this;
}
}

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>fit2cloud-commons</artifactId>
<groupId>com.fit2cloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>fit2cloud-common-db</artifactId>
<dependencies>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-starter.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>${flyway.version}</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${pagehelper.version}</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.30</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,117 @@
package com.fit2cloud.common.db;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class CodeGenerator {
/*private static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("请输入" + tip + "");
System.out.println(help.toString());
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StrUtil.isNotBlank(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输入正确的" + tip + "");
}*/
@Autowired
private Environment environment;
public void generator(String moduleName,String basePackage ,String tableName) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir")+"/"+moduleName;
//System.out.println(projectPath);
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("cyw");
gc.setOpen(false);
// gc.setSwagger2(true); 实体属性 Swagger2 注解
mpg.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
/*dsc.setUrl("jdbc:mysql://106.15.239.57:3306/data_ease?autoReconnect=false&useUnicode=true&characterEncoding=UTF-8&characterSetResults=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false");
dsc.setDriverName("com.mysql.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("Password123@mysql");*/
dsc.setUrl(environment.getProperty("spring.datasource.url"));
dsc.setDriverName(environment.getProperty("spring.datasource.driver-class-name"));
dsc.setUsername(environment.getProperty("spring.datasource.username"));
dsc.setPassword(environment.getProperty("spring.datasource.password"));
dsc.setTypeConvert(new MySqlTypeConvert());
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
/*pc.setModuleName(scanner("模块名"));*/
pc.setModuleName(basePackage);
pc.setParent("com.fit2cloud");
pc.setEntity("entity");
pc.setMapper("mapper");
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
// 如果模板引擎是 freemarker
String templatePath = "f2cmapper.java";
// 自定义输出配置
List<FileOutConfig> focList = new ArrayList<>();
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
// 配置模板
TemplateConfig templateConfig = new TemplateConfig();
templateConfig.setMapper(templatePath);
templateConfig.setService(null);
templateConfig.setServiceImpl(null);
templateConfig.setController(null);
templateConfig.setXml(null);
mpg.setTemplate(templateConfig);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true);
/*strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));*/
strategy.setInclude(tableName.split(","));
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix(pc.getModuleName() + "_");
strategy.setEntityTableFieldAnnotationEnable(true);
strategy.setSkipView(true);
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}

View File

@ -0,0 +1,17 @@
package com.fit2cloud.common.db;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class GeneratorApi {
@Autowired
private CodeGenerator codeGenerator;
@GetMapping("/generator/{moduleName}/{basePackage}/{tableName}")
public void generator(@PathVariable("moduleName") String moduleName, @PathVariable("basePackage") String basePackage, @PathVariable("tableName") String tableName){
codeGenerator.generator(moduleName, basePackage, tableName);
}
}

View File

@ -0,0 +1,29 @@
package com.fit2cloud.common.db;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisPlusConfig {
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题
*/
/*@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> configuration.setUseDeprecatedExecutor(false);
}*/
}

View File

@ -0,0 +1,18 @@
package com.fit2cloud.common.db;
import com.github.pagehelper.Page;
public class PageUtils {
public static <T> Pager<T> setPageInfo(Page page, T obj) {
try {
Pager<T> pager = new Pager<>();
pager.setListObject(obj);
pager.setPageCount(page.getPages());
pager.setItemCount(page.getTotal());
return pager;
} catch (Exception e) {
//LogUtil.error("Error saving current page number data:", e);
throw new RuntimeException("Error saving current page number data");
}
}
}

View File

@ -0,0 +1,19 @@
package com.fit2cloud.common.db;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Pager<T> {
private T listObject;
private long itemCount;
private long pageCount;
}

View File

@ -0,0 +1,6 @@
spring.flyway.enabled=true
spring.flyway.baseline-on-migrate=true
spring.flyway.table=f2c_version
spring.flyway.baseline-version=0
spring.flyway.encoding=UTF-8
spring.flyway.validate-on-migrate=false

View File

@ -0,0 +1,27 @@
package ${package.Mapper};
import ${package.Entity}.${entity};
import ${superMapperClassPackage};
<#if table.convert>
import org.apache.ibatis.annotations.Mapper;
</#if>
/**
* <p>
* ${table.comment!} Mapper 接口
* </p>
*
* @author ${author}
* @since ${date}
*/
<#if kotlin>
interface ${table.mapperName} : ${superMapperClass}<${entity}>
<#else>
<#if table.convert>
@Mapper
</#if>
public interface ${table.mapperName} extends ${superMapperClass}<${entity}> {
}
</#if>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>fit2cloud-commons</artifactId>
<groupId>com.fit2cloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>fit2cloud-common-logs</artifactId>
</project>

22
fit2cloud-commons/pom.xml Normal file
View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>fit2cloud-frame</artifactId>
<groupId>com.fit2cloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>fit2cloud-commons</artifactId>
<packaging>pom</packaging>
<modules>
<module>fit2cloud-common-auth</module>
<module>fit2cloud-common-base</module>
<module>fit2cloud-common-logs</module>
<module>fit2cloud-common-db</module>
</modules>
</project>

50
fit2cloud-system/pom.xml Normal file
View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>fit2cloud-frame</artifactId>
<groupId>com.fit2cloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>fit2cloud-system</artifactId>
<dependencies>
<dependency>
<groupId>com.fit2cloud</groupId>
<artifactId>fit2cloud-common-base</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.fit2cloud</groupId>
<artifactId>fit2cloud-common-auth</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.fit2cloud</groupId>
<artifactId>fit2cloud-common-db</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,18 @@
package com.fit2cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@EnableCaching
@SpringBootApplication
public class SystemApp {
public static void main(String[] args) {
SpringApplication.run(SystemApp.class);
}
}

View File

@ -0,0 +1,37 @@
package com.fit2cloud.system.api;
import com.fit2cloud.common.db.PageUtils;
import com.fit2cloud.common.db.Pager;
import com.fit2cloud.commons.auth.entity.User;
import com.fit2cloud.commons.auth.mapper.UserMapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class BusiApi {
@GetMapping("/busi/dashboard")
public Object dashboard(){
return "dashboard";
}
@Autowired
private UserMapper userMapper;
@GetMapping("/page")
public Object list(){
int startpage = 1;
int limit = 10;
Page<Object> page = PageHelper.startPage(startpage, limit);
List<User> users = userMapper.selectList(null);
Pager<List<User>> pageInfo = PageUtils.setPageInfo(page, users);
return pageInfo;
}
}

View File

@ -0,0 +1,15 @@
package com.fit2cloud.system.api;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SysApi {
@GetMapping("/sys/manager")
public Object manager(){
return "manager";
}
}

View File

@ -0,0 +1,54 @@
package com.fit2cloud.system.api;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class TestApi {
@GetMapping("/test")
public Object test(){
return "apple";
}
@GetMapping("/test1")
public Map<String, String> test1(){
Map<String, String> map = new HashMap<String, String>();
map.put("1", "a");
map.put("2", "b");
return map;
}
@RequiresPermissions("")
@GetMapping("/test2")
public Map<String, String> test2(){
//Map<String, String> map = new HashMap<String, String>();
Map<String, String> map = null;
try {
map.put("1", "a");
map.put("2", "b");
}catch (Exception e){
e.printStackTrace();
}
return map;
}
}

View File

@ -0,0 +1,6 @@
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:mysql://106.15.239.57:3306/data_ease?autoReconnect=false&useUnicode=true&characterEncoding=UTF-8&characterSetResults=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false
spring.datasource.username=root
spring.datasource.password=Password123@mysql
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
mybatis.mapper-locations=classpath:mapper/*.xml

View File

@ -0,0 +1,8 @@
CREATE TABLE test_users (
id bigint(20) NOT NULL AUTO_INCREMENT,
username varchar(100) NOT NULL,
first_name varchar(50) NOT NULL,
last_name varchar(50) DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY UK_username (username)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

View File

@ -0,0 +1,23 @@
package com.fit2cloud;
import com.fit2cloud.common.db.CodeGenerator;
import lombok.SneakyThrows;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class MyTest {
/*public static void main(String[] args) throws IOException {
ClassLoader classLoader = SystemApp.class.getClassLoader();
InputStream resourceAsStream = classLoader.getResourceAsStream("application.properties");
Properties properties = new Properties();
properties.load(resourceAsStream);
System.setProperties(properties);
CodeGenerator.test();
}*/
}

148
pom.xml Normal file
View File

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.fit2cloud</groupId>
<artifactId>fit2cloud-frame</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>fit2cloud-commons</module>
<module>fit2cloud-system</module>
</modules>
<packaging>pom</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<thymeleaf-extras-shiro.version>2.0.0</thymeleaf-extras-shiro.version>
<shiro.version>1.4.0</shiro.version>
<jwt.version>3.12.1</jwt.version>
<mybatis-starter.version>2.1.3</mybatis-starter.version>
<mybatis-plus.version>3.4.1</mybatis-plus.version>
<mybatis-generator.version>1.3.7</mybatis-generator.version>
<pagehelper.version>1.3.0</pagehelper.version>
<flyway.version>7.5.2</flyway.version>
<druid.version>1.2.4</druid.version>
<ehcache.version>2.6.9</ehcache.version>
<springfox-swagger2.version>2.9.0</springfox-swagger2.version>
<knife4j.version>2.0.5</knife4j.version>
<java.version>1.8</java.version>
<hutool.version>5.5.8</hutool.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
<plugin>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<attach>true</attach>
</configuration>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>jcenter-snapshots</id>
<name>jcenter</name>
<url>https://jcenter.bintray.com/</url>
</repository>
<repository>
<id>releases</id>
<name>Nexus Release Repository</name>
<url>http://repository.fit2cloud.com/content/repositories/releases/</url>
</repository>
<repository>
<id>fit2cloud-enterprise-release</id>
<name>Fit2Cloud Enterprise Release</name>
<url>http://repository.fit2cloud.com/content/repositories/fit2cloud-enterprise-release/</url>
</repository>
<repository>
<id>fit2cloud</id>
<name>fit2cloud</name>
<url>http://repository.fit2cloud.com/content/groups/public/</url>
</repository>
<repository>
<id>fit2cloud-public</id>
<name>fit2cloud-public</name>
<url>http://repository.fit2cloud.com/content/repositories/fit2cloud-public</url>
</repository>
</repositories>
<distributionManagement>
<repository>
<id>releases</id>
<name>Nexus Release Repository</name>
<url>http://repository.fit2cloud.com/content/repositories/releases/</url>
</repository>
<snapshotRepository>
<id>snapshots</id>
<name>Nexus Snapshot Repository</name>
<url>http://repository.fit2cloud.com/content/repositories/snapshots/</url>
</snapshotRepository>
</distributionManagement>
</project>