未验证 提交 fa11c428 编写于 作者: sinat_25235033's avatar sinat_25235033 提交者: GitHub

Feature general code explain (#41)

* update general code explain and clean code
上级 51642cad
......@@ -20,7 +20,8 @@ import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
/** 对用文件做持久层权限资源方式的默认配置
/**
* default sureness config, using file - sureness.yml as persistent layer permissions resources
* support servlet or jax-rs, default servlet
* @author tomsun28
* @date 11:26 2019-05-26
......
......@@ -12,7 +12,7 @@ import java.util.Set;
import java.util.stream.Collectors;
/**
* 默认的path - role 匹配 matcher实现
* default path - role matcher
* @author tomsun28
* @date 20:23 2019-03-10
*/
......@@ -28,34 +28,34 @@ public class DefaultPathRoleMatcher implements TreePathRoleMatcher {
private static final String EXCLUDE_ROLE = "exclude";
/** path-role 匹配树存储点 **/
/** path-role, match tree storage **/
private final TirePathTree root = new TirePathTree();
/** path-role 被排除的资源匹配树存储点 **/
/** exclude path-role, match tree storage **/
private final TirePathTree excludeRoot = new TirePathTree();
/** 匹配树数据内容提供者 **/
/** Match tree data content provider **/
private PathTreeProvider pathTreeProvider;
/** 是否匹配树数据加载完成 **/
/** Whether the matching tree data has been loaded **/
private volatile boolean isTreeInit;
@Override
public void matchRole(Subject auToken) {
public void matchRole(Subject subject) {
if (!isTreeInit) {
logger.error("DefaultPathRoleMatcher -> root tree is not init");
throw new SurenessNoInitException("DefaultPathRoleMatcher -> root tree is not init");
}
String targetResource = (String) auToken.getTargetResource();
String targetResource = (String) subject.getTargetResource();
//[role1,role2,role3], [role1], [], null
String matchRoleString = root.searchPathFilterRoles(targetResource);
if (matchRoleString != null && matchRoleString.startsWith(LEFT_CON)
&& matchRoleString.endsWith(RIGHT_CON)) {
if (NULL_ROLE.equals(matchRoleString)) {
auToken.setSupportRoles(new ArrayList<>(0));
subject.setSupportRoles(new ArrayList<>(0));
} else {
String[] roles = matchRoleString.substring(1, matchRoleString.length()-1).split(",");
auToken.setSupportRoles(Arrays.asList(roles));
subject.setSupportRoles(Arrays.asList(roles));
}
}
}
......
......@@ -3,22 +3,24 @@ package com.usthe.sureness.matcher;
import java.util.Set;
/**
* 资源的数据源
* path tree resource data provider
* @author tomsun28
* @date 22:30 2019-02-25
*/
public interface PathTreeProvider {
/**
* 加载URL资源的接口,可从数据库加载数据,文本加载数据等 eg: /api/v2/host===post===[role2,role3,role4]
* @return uri资源set
* Interface for loading URL resources.
* Can load data from database, text load data, etc.
* @return uri set, uri:eg: /api/v2/host===post===[role2,role3,role4]
* @throws SurenessLoadDataException when加载数据异常
*/
Set<String> providePathData();
/**
* 加载需要被过滤排除的URL资源的接口,同上,可从数据库或文本加载 eg: /api/v4/host===post
* @return uri资源集合: URL===METHOD
* Interface for loading URL exclude resources.
* Can load data from database, text load data, etc.
* @return uri set, uri: URL===METHOD, eg: /api/v4/host===post
*/
Set<String> provideExcludedResource();
}
......@@ -3,7 +3,7 @@ package com.usthe.sureness.matcher;
import com.usthe.sureness.processor.exception.ExtSurenessException;
/**
* 数据源加载异常
* datasource load exception
* @author tomsun28
* @date 00:00 2019-03-11
*/
......
......@@ -4,38 +4,38 @@ import com.usthe.sureness.mgt.SurenessNoInitException;
import com.usthe.sureness.subject.Subject;
/**
* path - role 匹配 matcher
* path-role matcher interface
* @author tomsun28
* @date 17:42 2019-03-10
*/
public interface TreePathRoleMatcher {
/**
* description : 通过auToken中的 targetUri 在树种匹配出所支持的roles 填充到token中
* @param auToken 根据接入对象所创建的TOKEN,成功后会将其所需角色塞入TOKEN
* Use the targetUri in the subject to match the supported roles in the tree and fill in the subject
* @param subject After success, the required role will be inserted into the subject
* @throws SurenessNoInitException when matcher not init
*/
void matchRole(Subject auToken);
void matchRole(Subject subject);
/**
* 建立起匹配树
* build the pathRole match tree
* @throws SurenessNoInitException when matcher not init
* @throws SurenessLoadDataException when 数据源 not init
* @throws SurenessLoadDataException when datasource not init
*/
void buildTree();
/**
* 重建匹配树
* rebuild the pathRole match tree
* @throws SurenessNoInitException when matcher not init
* @throws SurenessLoadDataException when 数据源 not init
* @throws SurenessLoadDataException when datasource not init
*/
void rebuildTree();
/**
* 通过拥有的排除资源名单判断这个请求所请求的资源是否在排除名单里
* 资源: requestUri===method
* @param request 请求内容
* @return 是排除资源true 否则false
* Determine whether the resource requested by this request is in the exclusion list
* resource: requestUri===method
* @param request request
* @return in the exclusion list return true, else false
*/
boolean isExcludedResource(Subject request);
}
......@@ -12,10 +12,11 @@ import java.util.Set;
import java.util.regex.Pattern;
/**
* 字典匹配树 支持 * **
* * 匹配零个或者1个目录
* ** 匹配零个或者多个目录
* 匹配优先级: 原始字符串 大于 * 大于 **
* Improved dictionary matching tree
* support regular * **
* the * can match zero or one directory
* the ** can match zero or more directories
* Match priority: Raw string > * > **
* @author tomsun28
* @date 19:25 2019-01-18
*/
......@@ -35,7 +36,7 @@ public class TirePathTree {
private static final Pattern PATH_SPLIT_PATTERN = Pattern.compile("/+");
/**
* 根节点
* root node
*/
private volatile Node root;
......@@ -44,8 +45,8 @@ public class TirePathTree {
}
/**
* 新建字典匹配树
* @param paths 资源路径
* build dictionary matching tree
* @param paths resource path set
*/
public synchronized void buildTree(Set<String> paths) {
if (logger.isDebugEnabled()) {
......@@ -61,9 +62,10 @@ public class TirePathTree {
}
/**
* 重建字典匹配树,更新字典树数据
* 保证重建时不影响读,并发方式RCU -- read copy update
* @param paths paths 资源
* rebuild and update dictionary matching tree
* Concurrency type:RCU -- read copy update
* Ensure that reading is not affected during reconstruction
* @param paths resources paths set
*/
public synchronized void rebuildTree(Set<String> paths) {
if (logger.isDebugEnabled()) {
......@@ -80,7 +82,7 @@ public class TirePathTree {
}
/**
* 清空字典树
* clear dictionary matching tree
*/
public void clearTree() {
if (logger.isDebugEnabled()) {
......@@ -90,12 +92,12 @@ public class TirePathTree {
}
/**
* 获取当前匹配树存在的匹配资源(URL+METHOD)数量
* @return int 资源数量
* Get the number of resources (URL+METHOD) in the current matching tree
* @return int resource number
*/
public int getResourceNum() {
int resourceNum = 0;
// 广度层级遍历
// Breadth First Search - bfs
Queue<Node> resourceList = new LinkedList<>();
resourceList.add(root);
while (!resourceList.isEmpty()) {
......@@ -114,9 +116,9 @@ public class TirePathTree {
}
/**
* 根据path从树里匹配该路径需要的 [role2,role3,role4]
* Use the resource path to match supported roles in tree
* @param path /api/v2/host/detail===get
* @return java.lang.String [role1,role2]
* @return java.lang.String roles eg: [role1,role2]
*/
public String searchPathFilterRoles(String path) {
if (path == null || "".equals(path) || !path.startsWith(URL_PATH_SPLIT)) {
......@@ -134,19 +136,19 @@ public class TirePathTree {
String[] urlPac = tmp[0].split("/");
String method = tmp[1];
// 模式匹配 * **
// Pattern matching * **
Node current = root;
return searchPathRoleInChildren(current, urlPac, -1, method);
}
/**
* 从当前node匹配查找对应分支的叶子节点
* @param current 当前node
* @param urlPac urlPath字符串组
* @param currentFlow 当前第一个字符串
* @param method http请求方法
* @return 匹配到返回[role,role2] 匹配不到返回null
* Find the leaf node of the corresponding branch from the current node
* @param current current node
* @param urlPac urlPath arr
* @param currentFlow current Flow
* @param method http method: post get delete put...
* @return match return roles eg:[role,role2], else return null
*/
private String searchPathRole(Node current, String[] urlPac, int currentFlow, String method) {
if (current == null || urlPac == null || currentFlow >= urlPac.length
......@@ -211,12 +213,12 @@ public class TirePathTree {
/**
* 从当前node匹配下一节点
* @param current 当前node
* @param urlPac urlPath字符串组
* @param currentFlow 当前第一个字符串
* @param method http请求方法
* @return 匹配到返回[role,role2] 匹配不到返回null
* Match the next node from the current node
* @param current current node
* @param urlPac urlPath arr
* @param currentFlow current flow
* @param method http method
* @return match return roles eg:[role,role2], else return null
*/
private String searchPathRoleInChildren(Node current, String[] urlPac, int currentFlow, String method) {
if (current == null || urlPac == null || currentFlow >= urlPac.length - 1
......@@ -247,10 +249,10 @@ public class TirePathTree {
}
/**
* 判断 pattern是否不匹配pathNode
* @param pattern 匹配串 * **
* @param pathNode 被匹配串
* @return 匹配失败 true 成功 false
* Determine whether the pattern does not match pathNode
* @param pattern pattern eg: * **
* @param pathNode pathNode
* @return match return true, else false
*/
private boolean isNoMatchString(String pattern, String pathNode) {
if (pattern == null && pathNode == null) {
......@@ -264,7 +266,7 @@ public class TirePathTree {
}
/**
* description 插入节点
* insert pathNode
* @param path path = /api/v1/host/detail===GET===[role2,role3,role4]
*/
private void insertNode(String path, Node rootNode) {
......@@ -275,7 +277,7 @@ public class TirePathTree {
logger.trace("sureness - begin insertNode, path is {}", path);
}
path = PATH_SPLIT_PATTERN.matcher(path).replaceAll("/");
// 去除第一个 /
// remove the first /
path = path.substring(1).toLowerCase();
String[] tmp = path.split("===");
if (tmp.length != PATH_NODE_NUM_3) {
......@@ -286,7 +288,7 @@ public class TirePathTree {
String supportRoles = tmp[2];
Node current = rootNode;
Node pre = current;
// 开始插入URL节点
// start inserting URL node
for (String urlData : urlPac) {
if (!current.getChildren().containsKey(urlData)) {
current.insertChild(urlData);
......@@ -295,36 +297,37 @@ public class TirePathTree {
current = current.getChildren().get(urlData);
}
if (MATCH_ONE.equals(current.getData()) || MATCH_ALL.equals(current.getData())) {
// 当倒数第一个为 * 或者 ** 时,其有可能匹配空,此时其前一个也可能为 NODE_TYPE_MAY_PATH_END
// When the last one is * or **, it may match empty,
// and the previous one may also be NODE_TYPE_MAY_PATH_END type
pre.setNodeType(NODE_TYPE_MAY_PATH_END);
}
// 设置NODE_TYPE_MAY_PATH_END节点类型
// set node type is NODE_TYPE_MAY_PATH_END
current.setNodeType(NODE_TYPE_MAY_PATH_END);
// 开始插入httpMethod节点,如果已经存在,则不覆盖修改原来配置
// start insert httpMethod method, if existed, not overwrite and modify the original configuration
if (!current.getChildren().containsKey(method)) {
current.insertChild(method, NODE_TYPE_METHOD);
}
current = current.getChildren().get(method);
// 开始插入叶子节点 supportRoles
// 每条资源只能对应一 supportRoles ,httpMethod下最多一个孩子节点
// 如果已经存在,则不覆盖修改原来配置
// Start inserting leaf nodes - supportRoles
// each resource only mapping a left node, that is, at most one child node under supportRoles--httpMethod
// if existed, not overwrite and modify the original configuration
if (current.getChildren().isEmpty()) {
current.insertChild(supportRoles, NODE_TYPE_FILTER_ROLES);
}
}
/**
* 树节点类
* Dictionary matching tree node
*/
private static class Node {
/** 当前节点的类型 **/
/** current node type **/
private String nodeType;
/** 节点对应的数据 **/
/** current node data **/
private String data;
/** 孩子节点 **/
/** children nodes **/
private Map<String, Node> children;
private Node(String data, String nodeType) {
......
......@@ -8,7 +8,7 @@ import com.usthe.sureness.processor.exception.BaseSurenessException;
import java.util.List;
/**
* 认证鉴权总方法调用入口接口
* Authentication authorization entrance interface
* @author tomsun28
* @date 22:33 2019-01-23
*/
......@@ -16,31 +16,27 @@ public interface SecurityManager {
/**
* description 通过不同类型的token进去到认证授权流程中
* 认证鉴权总入口, 不仅仅是login 还有鉴权
* @param token token
* auth entrance, put the subject in authentication and authorization process
* @param subject subject
* @return com.usthe.sureness.subject.Subject
* @throws BaseSurenessException 抛出不同的异常
* @throws BaseSurenessException sureness exception
*/
SubjectSum checkIn(Subject token) throws BaseSurenessException;
SubjectSum checkIn(Subject subject) throws BaseSurenessException;
/**
* description checkin 进入认证鉴权入口
*
* @param var1 请求内容对象
* auth entrance, put the request in authentication and authorization process
* @param var1 request
* @return com.usthe.sureness.subject.Subject
* return null when the request uri===method is in excluded resource
* @throws BaseSurenessException 抛出不同的认证鉴权异常
* @throws BaseSurenessException sureness exception
*/
SubjectSum checkIn(Object var1) throws BaseSurenessException;
/**
* description 传入请求信息,信息里有对应的请求认证消息,请求资源路径等 eg: httpRequest
* 根据请求信息获取建立对应类型的token
*
* @param var1 内容对象
* @return com.usthe.sureness.subject.SubjectAuToken
* @throws UnsupportedSubjectException 不支持的TOKEN时抛出异常
* Create the corresponding type of subject according to the request information
* @param var1 request eg: httpRequest
* @return com.usthe.sureness.subject.Subject
* @throws UnsupportedSubjectException unSupport this request
*/
List<Subject> createSubject(Object var1) throws UnsupportedSubjectException;
......
......@@ -4,7 +4,7 @@ package com.usthe.sureness.mgt;
import com.usthe.sureness.processor.exception.ExtSurenessException;
/**
* not init 异常
* sureness not init exception
* @author tomsun28
* @date 18:00 2019-03-10
*/
......
......@@ -14,7 +14,7 @@ import java.util.List;
/**
* 认证鉴权总方法调用默认入口类
* Authentication authorization entrance
* @author tomsun28
* @date 15:30 2019-03-03
*/
......@@ -23,17 +23,18 @@ public class SurenessSecurityManager implements SecurityManager {
private static final Logger logger = LoggerFactory.getLogger(SurenessSecurityManager.class);
/**
* subject 工厂
* subject factory
*/
private SubjectFactory subjectFactory;
/**
* path - role 在树中的对应关系匹配接口
* path-role match
* match role in pathRoleTree
*/
private TreePathRoleMatcher pathRoleMatcher;
/**
* 处理器管理者
* process manager
*/
private ProcessorManager processorManager;
......@@ -42,23 +43,24 @@ public class SurenessSecurityManager implements SecurityManager {
}
/**
* description 判断SecurityManager是否初始化完成并且组件加载成功
* Determine whether the SecurityManager is initialized
* and the component is loaded successfully
*
* @throws SurenessNoInitException check结果false 抛出异常
* @throws SurenessNoInitException check false not init
*/
private void checkComponentInit() {
if (subjectFactory == null || pathRoleMatcher == null ||
processorManager == null) {
logger.error("SecurityManager init error : SurenessSecurityManager not init fill component");
// 组件自己的相关异常或者配置行异常不往上抛出
// The component's own related exceptions or configuration line exceptions are not thrown up
throw new SurenessNoInitException("SurenessSecurityManager not init fill component");
}
}
@Override
public SubjectSum checkIn(Subject token) throws BaseSurenessException {
// 判断请求资源是否是配置的排除过滤资源
// 若是直接通行,返回NULL不抛异常
// Determine whether the requested resource is a filtered resource
// if yes, pass directly
if (pathRoleMatcher.isExcludedResource(token)) {
return null;
}
......@@ -70,13 +72,13 @@ public class SurenessSecurityManager implements SecurityManager {
public SubjectSum checkIn(Object var1) throws BaseSurenessException {
checkComponentInit();
// 创建subject list去一次一次认证鉴权尝试
// Create a subject list to try auth one by one
List<Subject> subjectList = createSubject(var1);
RuntimeException lastException = new UnsupportedSubjectException("this request can not " +
"create subject by creators");
// 对于创建的几个门面钥匙 一把一把试错
// 若钥匙都不对 抛异常在最后一把 即最后一把试错的结果为展示的错误信息
// for the subject keys, try one by one
// if one success, pass and return directly
for (Subject thisSubject : subjectList) {
try {
return checkIn(thisSubject);
......@@ -84,7 +86,7 @@ public class SurenessSecurityManager implements SecurityManager {
lastException = e;
}
}
// 尝试所有subject都失败 抛出最后一个异常
// if no one success, the throw exception is the lastException
throw lastException;
}
......@@ -118,7 +120,7 @@ public class SurenessSecurityManager implements SecurityManager {
}
/**
* 单例静态内部类
* singleton
* @author tomsun28
* @date 15:30 2019-03-10
*/
......
......@@ -6,28 +6,28 @@ import com.usthe.sureness.subject.SubjectSum;
import com.usthe.sureness.subject.Subject;
/**
* abstract processor
* @author tomsun28
* @date 12:28 2019-03-13
*/
public abstract class BaseProcessor implements Processor{
/**
* description 判断此Processor是否支持对应的AuTokenClass
* 支持才能让此Processor处理对应的AuTokenClass
* Determine whether this Processor supports the corresponding SubjectClass
*
* @param var 1
* @return boolean
* @param var subjectClass
* @return support true, else false
*/
@Override
public abstract boolean canSupportAuTokenClass(Class<?> var);
public abstract boolean canSupportSubjectClass(Class<?> var);
/**
* description 获取此Processor能支持的AuTokenClass
* Get the subjectClass supported by this processor
*
* @return java.lang.Class?
* @return java.lang.Class? subjectClass
*/
@Override
public abstract Class<?> getSupportAuTokenClass();
public abstract Class<?> getSupportSubjectClass();
@Override
public SubjectSum process(Subject var) throws SurenessAuthenticationException, SurenessAuthorizationException {
......@@ -35,17 +35,17 @@ public abstract class BaseProcessor implements Processor{
return var.generateSubjectSummary();
}
/**
* description 认证会调用的接口,在这里面完成认证
* @param var 1
* @return SubjectAuToken auToken
* @throws SurenessAuthenticationException when发生认证相关异常
* The interface that the authentication will call to complete the authentication
* @param var subject
* @return Subject subject
* @throws SurenessAuthenticationException when authenticate error
*/
public abstract Subject authenticated (Subject var) throws SurenessAuthenticationException;
/**
* description 鉴权会调用的接口,在这里面完成鉴权
* @param var 1
* @throws SurenessAuthorizationException when发生鉴权相关异常
* The interface that the authorization will call, where the authorization is completed
* @param var subject
* @throws SurenessAuthorizationException when authorize error
*/
public abstract void authorized(Subject var) throws SurenessAuthorizationException;
}
......@@ -12,6 +12,7 @@ import org.slf4j.LoggerFactory;
import java.util.List;
/**
* sureness default process manager
* @author tomsun28
* @date 22:21 2019-03-10
*/
......@@ -26,35 +27,35 @@ public class DefaultProcessorManager implements ProcessorManager {
}
@Override
public SubjectSum process(Subject auToken) throws SurenessAuthenticationException, SurenessAuthorizationException {
public SubjectSum process(Subject subject) throws SurenessAuthenticationException, SurenessAuthorizationException {
checkComponentInit();
SurenessAuthenticationException lastAuthenticationException = null;
SurenessAuthorizationException lastAuthorizationException = null;
SubjectSum subjectResult = null;
Class<? extends Subject> auTokenClazz = auToken.getClass();
Class<? extends Subject> subjectClazz = subject.getClass();
// 对process链 一个process成功即可
// Process chain cyclic processing, one process can be successful
for (Processor processor : getProcessorList()) {
if (processor.canSupportAuTokenClass(auTokenClazz)) {
if (processor.canSupportSubjectClass(subjectClazz)) {
try {
subjectResult = processor.process(auToken);
subjectResult = processor.process(subject);
} catch (SurenessAuthenticationException var1) {
lastAuthenticationException = var1;
} catch (SurenessAuthorizationException var2) {
lastAuthorizationException = var2;
}
}
// 如果此次process 认证鉴权成功返回结果
// if process auth success, return
if (subjectResult != null) {
return subjectResult;
}
}
// 如果最终异常都为空 ,说明没有processor匹配到token
// if last exception is null, means that no processor matches the subject
if (lastAuthenticationException == null && lastAuthorizationException == null) {
if (logger.isDebugEnabled()) {
logger.debug("not found token : {} -- target processor", auToken.getClass() );
logger.debug("not found token : {} -- target processor", subject.getClass() );
}
throw new ProcessorNotFoundException("not found token : " + auToken.getClass()
throw new ProcessorNotFoundException("not found token : " + subject.getClass()
+ " --target processor");
}
throw lastAuthenticationException == null ? lastAuthorizationException : lastAuthenticationException;
......
......@@ -6,34 +6,34 @@ import com.usthe.sureness.subject.SubjectSum;
import com.usthe.sureness.subject.Subject;
/**
* 处理器,处理传进来的认证对象,对其进行认证账号与权限
* processor
* Process the incoming authentication object, and verify the account and authority of it
* @author tomsun28
* @date 21:54 2019-03-06
*/
public interface Processor {
/**
* description 判断此Processor是否支持对应的AuTokenClass
* 支持才能让此Processor处理对应的AuTokenClass
* Determine whether this Processor supports the corresponding SubjectClass
*
* @param var 1
* @return boolean
* @param var subjectClass
* @return support true, else false
*/
boolean canSupportAuTokenClass(Class<?> var);
boolean canSupportSubjectClass(Class<?> var);
/**
* description 获取此Processor能支持的AuTokenClass
* Get the subjectClass supported by this processor
*
* @return java.lang.Class?
* @return java.lang.Class? subjectClass
*/
Class<?> getSupportAuTokenClass();
Class<?> getSupportSubjectClass();
/**
* description 进入处理
* @param var 1
* @throws SurenessAuthenticationException when
* @throws SurenessAuthorizationException when
* process the subject
* @param var subject
* @throws SurenessAuthenticationException when Authentication error
* @throws SurenessAuthorizationException when Authorization error
* @return com.usthe.sureness.subject.Subject
*/
SubjectSum process(Subject var) throws SurenessAuthenticationException, SurenessAuthorizationException;
......
......@@ -4,17 +4,17 @@ import com.usthe.sureness.subject.SubjectSum;
import com.usthe.sureness.subject.Subject;
/**
* 处理器管理
* processor manager
* @author tomsun28
* @date 17:53 2019-03-10
*/
public interface ProcessorManager {
/**
* description 处理器处理token入口
* The entry which processor handles subject
*
* @param auToken 1
* @param subject subject
* @return com.usthe.sureness.subject.Subject
*/
SubjectSum process(Subject auToken);
SubjectSum process(Subject subject);
}
package com.usthe.sureness.processor.exception;
/**
* sureness基础异常,其他异常继承此类
* sureness basic exception, other exceptions inherit this exception
* @author tomsun28
* @date 22:40 2019-01-23
*/
......
package com.usthe.sureness.processor.exception;
/**
* 认证异常:禁用锁定账户异常
* Authentication exception: Disable lock account exception
* @author tomsun28
* @date 19:23 2019-03-11
*/
......
package com.usthe.sureness.processor.exception;
/**
* 认证异常:常规认证失败后尝试次数太多异常
* Authentication exception: Too many attempts after regular authentication failure
* @author tomsun28
* @date 19:24 2019-03-11
*/
......
package com.usthe.sureness.processor.exception;
/**
* 认证异常:过期的凭证
* Authentication exception: Expired certificate
* @author tomsun28
* @date 19:22 2019-03-11
*/
......
package com.usthe.sureness.processor.exception;
/**
* 扩展Sureness异常 此类异常与其子异常同 sureness 内部配置或组件本身异常相关
* Extended Sureness exception.
* Related to the internal configuration of sureness or the component itself.
* @author tomsun28
* @date 16:30 2020-02-28
*/
......
package com.usthe.sureness.processor.exception;
/**
* 认证异常:错误的凭证
* Authentication exception: Bad credentials
* @author tomsun28
* @date 19:21 2019-03-11
*/
......
package com.usthe.sureness.processor.exception;
/**
* 认证异常:认证鉴权中没有找到对应token支持的Processor
* Authentication exception: there is no processor support this subject
* @author tomsun28
* @date 12:50 2019-03-12
*/
......
package com.usthe.sureness.processor.exception;
/**
* 认证异常,为基础异常,自定义认证相关的sureness异常需要继承此类
* Authentication exception
* Basic exceptions, exceptions related to custom authentication need to inherit
* @author tomsun28
* @date 12:59 2019-03-11
*/
......
package com.usthe.sureness.processor.exception;
/**
* 鉴权异常:基础异常,自定义鉴权相关的异常需要继承此类
* Authorization exception
* Basic exceptions, exceptions related to custom authorization need to inherit
* @author tomsun28
* @date 13:00 2019-03-11
*/
......
package com.usthe.sureness.processor.exception;
/**
* 鉴权异常:没有访问对应资源的权限异常
* Authorization exception: No permission to access the resource
* @author tomsun28
* @date 19:25 2019-03-11
*/
......
package com.usthe.sureness.processor.exception;
/**
* 认证异常:未知的账户异常
* Authentication exception: Unknown account exception
* @author tomsun28
* @date 19:22 2019-03-11
*/
......
package com.usthe.sureness.processor.exception;
/**
* 认证异常:不支持的TOKEN类型
* 出现此错误说明加载的 subjectCreator list都无法根据请求创建对应的subject
* Authentication exception: Can not support this request
* SubjectCreator list unable to create the corresponding subject according to the request
* @author tomsun28
* @date 19:23 2019-03-11
*/
......
......@@ -15,7 +15,7 @@ import java.security.NoSuchAlgorithmException;
import java.util.List;
/**
* process digest auth
* process digest auth - DigestSubject
* @author tomsun28
* @date 2020-10-28 23:17
*/
......@@ -42,12 +42,12 @@ public class DigestProcessor extends BaseProcessor {
}
@Override
public boolean canSupportAuTokenClass(Class<?> var) {
public boolean canSupportSubjectClass(Class<?> var) {
return var == DigestSubject.class;
}
@Override
public Class<?> getSupportAuTokenClass() {
public Class<?> getSupportSubjectClass() {
return DigestSubject.class;
}
......
......@@ -20,7 +20,7 @@ import org.slf4j.LoggerFactory;
import java.util.List;
/**
* 支持 appId + jwt 的token的处理器实例
* the processor support jwt - JwtSubject
* @author tomsun28
* @date 12:36 2019-03-13
*/
......@@ -29,12 +29,12 @@ public class JwtProcessor extends BaseProcessor {
private static final Logger logger = LoggerFactory.getLogger(JwtProcessor.class);
@Override
public boolean canSupportAuTokenClass(Class<?> var) {
public boolean canSupportSubjectClass(Class<?> var) {
return var == JwtSubject.class;
}
@Override
public Class<?> getSupportAuTokenClass() {
public Class<?> getSupportSubjectClass() {
return JwtSubject.class;
}
......@@ -49,14 +49,14 @@ public class JwtProcessor extends BaseProcessor {
try {
claims = JsonWebTokenUtil.parseJwt(jwt);
} catch (SignatureException | UnsupportedJwtException | MalformedJwtException | IllegalArgumentException e) {
// JWT令牌错误
// JWT error
if (logger.isDebugEnabled()) {
logger.debug("jwtProcessor authenticated fail, user: {}, jwt: {}",
var.getPrincipal(), jwt);
}
throw new IncorrectCredentialsException("this jwt error:" + e.getMessage());
} catch (ExpiredJwtException e) {
// JWT 令牌过期
// JWT expired
if (logger.isDebugEnabled()) {
logger.debug("jwtProcessor authenticated expired, user: {}, jwt: {}",
var.getPrincipal(), jwt);
......
......@@ -12,22 +12,23 @@ import org.slf4j.LoggerFactory;
import java.util.List;
/** the processor support nonToken 处理非账户访问
/**
* the processor support nonToken
* @author tomsun28
* @date 21:12 2019-05-26
*/
public class NoneProcessor extends BaseProcessor {
/** 日志操作 **/
/** logger **/
private static final Logger logger = LoggerFactory.getLogger(NoneProcessor.class);
@Override
public boolean canSupportAuTokenClass(Class<?> var) {
public boolean canSupportSubjectClass(Class<?> var) {
return var == NoneSubject.class;
}
@Override
public Class<?> getSupportAuTokenClass() {
public Class<?> getSupportSubjectClass() {
return NoneSubject.class;
}
......
......@@ -19,7 +19,7 @@ import org.slf4j.LoggerFactory;
import java.util.List;
/**
* 支持 username password 类型token的处理器实例
* the processor support username password - PasswordSubject
* @author tomsun28
* @date 12:38 2019-03-13
*/
......@@ -30,13 +30,13 @@ public class PasswordProcessor extends BaseProcessor {
private SurenessAccountProvider accountProvider;
@Override
public boolean canSupportAuTokenClass(Class<?> var) {
public boolean canSupportSubjectClass(Class<?> var) {
return var == PasswordSubject.class;
}
@Override
public Class<?> getSupportAuTokenClass() {
// 这里只支持passwordToken -- username/appId/email/phoneNum + password
public Class<?> getSupportSubjectClass() {
// only support passwordToken -- username/appId/email/phoneNum + password
return PasswordSubject.class;
}
......
......@@ -3,28 +3,28 @@ package com.usthe.sureness.provider;
import java.util.List;
/**
* 账户实现
* account default
* @author tomsun28
* @date 16:20 2019-05-19
*/
public class DefaultAccount implements SurenessAccount {
/** 账户标识 **/
/** appId **/
private String appId;
/** 密码 **/
/** password **/
private String password;
/** 盐值 **/
/** salt **/
private String salt;
/** 所拥有的角色 **/
/** the roles owned by this account **/
private List<String> ownRoles;
/** 是否禁用账户 **/
/** if is a disable account **/
private boolean disabledAccount;
/** 是否一定时间内认证次数过多暂时禁用账户认证 **/
/** if is excessive attempt **/
private boolean excessiveAttempts;
private DefaultAccount(Builder builder) {
......
......@@ -4,44 +4,46 @@ package com.usthe.sureness.provider;
import java.util.List;
/**
* account for sureness
* @author tomsun28
* @date 23:18 2019-04-02
*/
public interface SurenessAccount {
/**
* 获取用户的标识
* @return 用户标识
* get appId, identifier
* @return appId
*/
String getAppId();
/**
* 获取用户的账户密码
* @return 账户密码
* get user password
* @return password
*/
String getPassword();
/**
* 获取盐
* @return 加盐
* get salt
* @return salt
*/
String getSalt();
/**
* 获取用户所拥有的角色
* @return 拥有的角色
* get the roles owned by this account
* @return roles
*/
List<String> getOwnRoles();
/**
* 是否是禁用账户
* @return 是禁用账户返回true 不是返回false
* if is a disable account
* @return disable return true, else false
*/
boolean isDisabledAccount();
/**
* 是否常规认证失败后尝试次数太多,超过系统设定的次数
* @return 是常规认证次数达到阈值,账户暂时不能使用,返回true 否则返回false
* Whether there are too many attempts after routine authentication failure,
* exceeding the number set by the system
* @return yes return true, else false
*/
boolean isExcessiveAttempts();
......
package com.usthe.sureness.provider;
/**
* 账户加载接口类
* load account data interface
* @author tomsun28
* @date 23:02 2019-04-02
*/
public interface SurenessAccountProvider {
/**
* 从数据库或者其他持久层加载对应用户的账户信息
* @param appId 账户标识
* @return 账户信息
* load account information from database, file or other persistence layer
* @param appId account appId
* @return account information
*/
SurenessAccount loadAccount(String appId);
......
......@@ -12,6 +12,7 @@ import java.util.List;
import java.util.Set;
/**
* use annotation load sureness pathTree config data
* @author tomsun28
* @date 23:57 2020-03-16
*/
......@@ -20,17 +21,17 @@ public class AnnotationLoader implements PathTreeProvider {
private static final Logger logger = LoggerFactory.getLogger(AnnotationLoader.class);
/**
* 注解的指定扫描包
* Specified scan package
*/
private List<String> scanPackages;
/**
* 扫描出来的class
* Scanned class
*/
private List<Class<?>> scanClasses;
/**
* 是否初始化
* if is init
*/
private volatile boolean isInit = false;
......
......@@ -6,7 +6,8 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 接口权限修饰注解,被修饰的接口支持roles内角色访问
* sureness annotation
* The modified resource with @RequiresRoles can be accessed when user role in [roles]
* @author tomsun28
* @date 23:22 2020-03-16
*/
......@@ -15,19 +16,19 @@ import java.lang.annotation.Target;
public @interface RequiresRoles {
/**
* 所支持角色
* support roles
* @return roles
*/
String[] roles() default {};
/**
* 请求路径
* request uri
* @return uri
*/
String mapping();
/**
* 请求方式
* request method
* @return method - post,get,put,delete ...
*/
String method();
......
......@@ -6,7 +6,8 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 接口认证修饰注解,被修饰的接口不需要认证保护即可访问
* sureness annotation
* The modified resource with @WithoutAuth can be accessed without authentication protection
* @author tomsun28
* @date 23:38 2020-03-16
*/
......@@ -15,13 +16,13 @@ import java.lang.annotation.Target;
public @interface WithoutAuth {
/**
* 请求路径
* request uri mapping
* @return uri
*/
String mapping();
/**
* 请求方式
* request method
* @return method - post,get,put,delete ...
*/
String method();
......
......@@ -9,7 +9,7 @@ import java.io.IOException;
import java.io.InputStream;
/**
* 资源文件里内容的操作类
* Operation content in resource document file - sureness.yml
* @author tomsun28
* @date 21:41 2019-05-24
*/
......@@ -17,7 +17,7 @@ public class DocumentResourceAccess {
private static final String DEFAULT_FILE_NAME = "sureness.yml";
/** 默认的资源文件名称位置 sureness.yml **/
/** default resource document file name - sureness.yml **/
private static String yamlFileName;
static {
......@@ -25,9 +25,9 @@ public class DocumentResourceAccess {
}
/**
* 从配置文件里读取resource配置信息
* @return 配置实体对象
* @throws IOException 文件不存在或者读取文件异常时
* load config information form document
* @return config object
* @throws IOException When the file does not exist or the file is read abnormally
*/
public static DocumentResourceEntity loadConfig() throws IOException {
Yaml yaml = new Yaml();
......@@ -51,7 +51,7 @@ public class DocumentResourceAccess {
/**
* config file path name
* @param fileName 文件路径名称
* @param fileName file path name
*/
public static void setYamlName(String fileName) {
yamlFileName = fileName;
......
......@@ -22,7 +22,7 @@ import java.util.Set;
*/
public class DocumentResourceDefaultProvider implements PathTreeProvider, SurenessAccountProvider {
/** 日志操作 **/
/** logger **/
private static final Logger logger = LoggerFactory.getLogger(DocumentResourceDefaultProvider.class);
private static final String CREDENTIAL = "credential";
......@@ -31,7 +31,7 @@ public class DocumentResourceDefaultProvider implements PathTreeProvider, Surene
private static final String ROLE = "role";
/** sureness配置信息内存缓存 **/
/** sureness config memory cache **/
private DocumentResourceEntity entity;
@Override
......
......@@ -4,7 +4,7 @@ import java.util.List;
import java.util.Map;
/**
* 从yaml文件加载的资源实体 默认文件 sureness.yaml
* sureness config information entity
* @author tomsun28
* @date 21:34 2019-05-24
*/
......
......@@ -7,58 +7,57 @@ import java.io.Serializable;
import java.util.List;
/**
* AuthenticationToken AuthorizationToken 认证鉴权对象
* AuthenticationToken AuthorizationToken subject
* @author tomsun28
* @date 21:58 2019-01-22
*/
public interface Subject extends Serializable {
/**
* description 账户名 string
* account appId, eg:username
*
* @return 账户标识
* @return identifier appId
*/
Object getPrincipal();
/**
* description 认证证书
* account credential, eg:password
*
* @return 对应账户的认证证书或秘钥
* @return credential
*/
Object getCredentials();
/**
* description 对应账户所拥有的角色
* get the roles owned by this account
*
* @return 角色信息
* @return roles
*/
Object getOwnRoles();
/**
* description 需要访问的资源
* get the target resource uri which this account want access
*
* @return 资源信息
* @return resource uri
*/
Object getTargetResource();
/**
* description 获取token 在url-role树中匹配出来的roles
* null表示没有匹配出url,数据集合为0表示匹配出来需要的role为空,即支持所有role
* 访问 getTargetResource() 所支持的 roles
* get the Roles which can access this resource above-targetUri
*
* @return 访问此资源所需的角色信息
* @return roles
*/
Object getSupportRoles();
/**
* description 设置所匹配出的role
* set the Roles which can access this resource above-targetUri
*
* @param var1 所支持角色
* @param var1 support roles
*/
void setSupportRoles(Object var1);
/**
* description 通过 自身subject内容创建对应精简内容的subjectSum
*
* Simplify content subject to create subjectSummary
*
* @return com.usthe.sureness.subject.Subject
*/
......
package com.usthe.sureness.subject;
/**
* 不同类型的subject创建
* subject creator interface
* creator subject
* @author tomsun28
* @date 23:44 2020-02-27
*/
......@@ -9,16 +10,16 @@ public interface SubjectCreate {
/**
* 通过获取context简明信息,初步判断是否能支持这种类型的subject创建
* 初步判断,原则是:特征通过则true
* @param context 请求主体内容
* @return 判断能创建此类型true 否则false
* By obtaining concise input context information,
* determine whether it can support this type of subject creation
* @param context request context
* @return can support return true, else false
*/
boolean canSupportSubject(Object context);
/**
* 通过context获取信息创建对应类型的subject
* @param context 请求主体内容
* Create a subject by obtaining the context content
* @param context request context
* @return subject return null when can not create by context
*/
Subject createSubject(Object context);
......
......@@ -3,29 +3,28 @@ package com.usthe.sureness.subject;
import java.util.List;
/**
* subject 工厂
* subject工厂可以创建多个Subject 就像有多个钥匙 其中有几个都是正确的
* 改为注册式 把创建的subject creator 注册到工厂 这样user也可以自定义creator
* subject factory, can create multi subject by subject creators
* the factory is registered, the subject creators register them in this factory
* @author tomsun28
* @date 00:39 2019-01-24
*/
public interface SubjectFactory {
/**
* description 通过加载的creators去创建其所支持的subject
* @param var1 请求对象内容
* @return com.usthe.sureness.subject.SubjectAuToken return 0 list when can not create subject from var1
* Create the subject supported by the loaded creators
* @param var1 request body
* @return com.usthe.sureness.subject.Subject return 0 list when can not create subject from var1
*/
List<Subject> createSubjects(final Object var1);
/**
* 向工厂注册subject的creators
* register subject creator to factory
* @param creators subject creator list
*/
void registerSubjectCreator(List<SubjectCreate> creators);
/**
* 加载已经存在于工厂的creators出来使用
* load the subject creators
* @return creators
*/
List<SubjectCreate> loadSubjectCreators();
......
......@@ -4,44 +4,42 @@ import java.io.Serializable;
import java.util.Collection;
/**
* Subject 简单概要 包含一些基本信息内容
* Subject summary, contains some basic information content
* @author tomsun28
* @date 22:59 2019-01-09
*/
public interface SubjectSum extends Serializable {
/**
* description 获取认证对象的账户
* Get the account of the authentication object
* @return java.lang.Object
*/
Object getPrincipal();
/**
* description 是否有特定角色
* Determine whether it has role - var1
*
* @param var1 1
* @return boolean
* @param var1 role
* @return boolean has-true, no have - false
*/
boolean hasRole(String var1);
/**
* description 是否有对应全部角色
*
* @param var1 1
* @return boolean
* Determine whether it has all roles - var1
* @param var1 role list
* @return boolean has-true, no have - false
*/
boolean hasAllRoles(Collection<String> var1);
/**
* description 获取拥有的角色
* get the roles owned by it
*
* @return java.lang.Object
*/
Object getRoles();
/**
* description 获取这次想访问目标资源
*
* get the target resource uri which it want access
* @return java.lang.Object
*/
Object getTargetResource();
......
......@@ -11,7 +11,7 @@ import java.nio.charset.StandardCharsets;
import java.util.Base64;
/**
* 支持通过basic auth 创建PasswordSubject 的创建者
* the subject creator support creating PasswordSubject
* only support JAX-RS
* @author tomsun28
* @date 23:53 2020-09-20
......@@ -26,7 +26,6 @@ public class BasicSubjectJaxRsCreator implements SubjectCreate {
@Override
public boolean canSupportSubject(Object context) {
// basic auth判断
// ("Authorization", "Basic YWRtaW46YWRtaW4=") --- basic auth
if (context instanceof ContainerRequestContext) {
String authorization = ((ContainerRequestContext)context).getHeaderString(AUTHORIZATION);
......
......@@ -11,7 +11,7 @@ import java.nio.charset.StandardCharsets;
import java.util.Base64;
/**
* 支持通过basic auth 创建PasswordSubject 的创建者
* the subject creator support creating PasswordSubject
* only support HttpServletRequest
* @author tomsun28
* @date 23:53 2020-02-27
......@@ -26,7 +26,6 @@ public class BasicSubjectServletCreator implements SubjectCreate {
@Override
public boolean canSupportSubject(Object context) {
// basic auth判断
// ("Authorization", "Basic YWRtaW46YWRtaW4=") --- basic auth
if (context instanceof HttpServletRequest) {
String authorization = ((HttpServletRequest)context).getHeader(AUTHORIZATION);
......
......@@ -12,7 +12,8 @@ import java.util.HashMap;
import java.util.Map;
/**
* digest subject creator
* the subject creator support creating DigestSubject
* only support JAX-RS
* @author tomsun28
* @date 2020-10-28 20:44
*/
......
......@@ -12,7 +12,8 @@ import java.util.HashMap;
import java.util.Map;
/**
* digest subject creator
* the subject creator support creating DigestSubject
* only support HttpServletRequest
* @author tomsun28
* @date 2020-10-28 20:44
*/
......
......@@ -11,7 +11,7 @@ import javax.ws.rs.container.ContainerRequestContext;
/**
* JwtSubject creator
* the subject creator support creating JwtSubject
* only support JAX-RS
* @author tomsun28
* @date 23:58 2020-02-27
......
......@@ -10,7 +10,7 @@ import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
/**
* JwtSubject creator
* the subject creator support creating JwtSubject
* only support HttpServletRequest
* @author tomsun28
* @date 23:58 2020-02-27
......
......@@ -7,8 +7,8 @@ import com.usthe.sureness.subject.support.NoneSubject;
import javax.ws.rs.container.ContainerRequestContext;
/**
* 无认证信息的subject creator
* 所有请求都能创建出一个NoneSubject
* the subject creator support creating NoneSubject
* all request content can create a NoneSubject
* only support JAX-RS
* @author tomsun28
* @date 15:55 2020-02-28
......
......@@ -7,8 +7,8 @@ import com.usthe.sureness.subject.support.NoneSubject;
import javax.servlet.http.HttpServletRequest;
/**
* 无认证信息的subject creator
* 所有请求都能创建出一个NoneSubject
* the subject creator support creating NoneSubject
* all request content can create a NoneSubject
* only support HttpServletRequest
* @author tomsun28
* @date 15:55 2020-02-28
......
......@@ -13,43 +13,43 @@ public class DigestSubject implements Subject {
private static final long serialVersionUID = 1L;
/** 用户标识 **/
/** appId, account identifier **/
private String appId;
/** 安全域 **/
/** account realm **/
private String realm;
/** uri **/
private String uri;
/** 保护质量,包含auth(默认的)和 auth-int **/
/** qop,include auth(default) and auth-int **/
private String qop;
/** 服务端向客户端发送质询时附带的一个随机数 **/
/** A random number attached when the server sends a challenge to the client **/
private String nonce;
/** nonce计数器,是一个16进制的数值 **/
/** nonce counter, is a hexadecimal value **/
private String nc;
/** 客户端随机数 **/
/** Client random number **/
private String cnonce;
/** 加密后的口令 **/
/** Encrypted password **/
private String response;
/** 请求的http method **/
/** http method **/
private String httpMethod;
/** 访问用户的IP **/
/** remote IP **/
private String remoteHost;
/** 所拥有的角色 在解析完jwt之后把用户角色放到这里 **/
/** the roles which this user owned **/
private List<String> ownRoles;
/** 所访问资源地址 **/
/** the uri resource which this user want access **/
private String targetUri;
/** 所访问资源他支持的角色 **/
/** the Roles which can access this resource above-targetUri **/
private List<String> supportRoles;
public DigestSubject() {}
......@@ -137,8 +137,8 @@ public class DigestSubject implements Subject {
return new DigestSubject.Builder(username, response);
}
public static DigestSubject.Builder builder(Subject auToken) {
return new DigestSubject.Builder(auToken);
public static DigestSubject.Builder builder(Subject subject) {
return new DigestSubject.Builder(subject);
}
public static class Builder {
......@@ -163,12 +163,12 @@ public class DigestSubject implements Subject {
}
@SuppressWarnings("unchecked")
public Builder(Subject auToken) {
this.appId = String.valueOf(auToken.getPrincipal());
this.response = String.valueOf(auToken.getCredentials());
this.ownRoles = (List<String>) auToken.getOwnRoles();
this.targetUri = String.valueOf(auToken.getTargetResource());
this.supportRoles = (List<String>) auToken.getSupportRoles();
public Builder(Subject subject) {
this.appId = String.valueOf(subject.getPrincipal());
this.response = String.valueOf(subject.getCredentials());
this.ownRoles = (List<String>) subject.getOwnRoles();
this.targetUri = String.valueOf(subject.getTargetResource());
this.supportRoles = (List<String>) subject.getSupportRoles();
}
public DigestSubject.Builder setAppId(String appId) {
......
......@@ -5,7 +5,7 @@ import com.usthe.sureness.subject.Subject;
import java.util.List;
/**
* 支持JWT AUTH 的TOKEN
* the subject support jwt auth
* @author tomsun28
* @date 12:28 2019-03-14
*/
......@@ -13,25 +13,25 @@ public class JwtSubject implements Subject {
private static final long serialVersionUID = 1L;
/** 用户的标识 **/
/** appId **/
private String appId;
/** json web token **/
/** json web token **/
private String jwt;
/** 访问用户的IP **/
/** remote ip **/
private String remoteHost;
/** 访问用户的设备信息 **/
/** remote device **/
private String userAgent;
/** 所拥有的角色 在解析完jwt之后把用户角色放到这里 **/
/** the roles which this user owned **/
private List<String> ownRoles;
/** 所访问资源地址 **/
/** the uri resource which this user want access **/
private String targetUri;
/** 所访问资源他支持的角色 **/
/** the Roles which can access this resource above-targetUri **/
private List<String> supportRoles;
private JwtSubject(Builder builder) {
......@@ -87,8 +87,8 @@ public class JwtSubject implements Subject {
return new Builder(jwt);
}
public static Builder builder(Subject auToken) {
return new Builder(auToken);
public static Builder builder(Subject subject) {
return new Builder(subject);
}
public static class Builder {
......@@ -106,12 +106,12 @@ public class JwtSubject implements Subject {
}
@SuppressWarnings("unchecked")
public Builder(Subject auToken) {
this.appId = String.valueOf(auToken.getPrincipal());
this.jwt = String.valueOf(auToken.getCredentials());
this.ownRoles = (List<String>) auToken.getOwnRoles();
this.targetUri = String.valueOf(auToken.getTargetResource());
this.supportRoles = (List<String>) auToken.getSupportRoles();
public Builder(Subject subject) {
this.appId = String.valueOf(subject.getPrincipal());
this.jwt = String.valueOf(subject.getCredentials());
this.ownRoles = (List<String>) subject.getOwnRoles();
this.targetUri = String.valueOf(subject.getTargetResource());
this.supportRoles = (List<String>) subject.getSupportRoles();
}
public Builder setPrincipal(String appId) {
......
......@@ -5,7 +5,7 @@ import com.usthe.sureness.subject.Subject;
import java.util.List;
/**
* 无认证信息的subject
* Subject without authentication information
* @author tomsun28
* @date 21:03 2019-05-26
*/
......@@ -13,16 +13,16 @@ public class NoneSubject implements Subject {
private static final long serialVersionUID = 1L;
/** 访问用户的IP **/
/** remote ip **/
private String remoteHost;
/** 访问用户的设备信息 **/
/** remote device **/
private String userAgent;
/** 所访问资源地址 **/
/** the uri resource which this user want access **/
private String targetUri;
/** 所访问资源他支持的角色 **/
/** the Roles which can access this resource above-targetUri **/
private List<String> supportRoles;
private NoneSubject(Builder builder) {
......@@ -77,16 +77,12 @@ public class NoneSubject implements Subject {
public static class Builder {
/** 访问用户的IP **/
private String remoteHost;
/** 访问用户的设备信息 **/
private String userAgent;
/** 所访问资源地址 **/
private String targetUri;
/** 所访问资源他支持的角色 **/
private List<String> supportRoles;
public Builder setRemoteHost(String remoteHost) {
......
......@@ -5,7 +5,7 @@ import com.usthe.sureness.subject.Subject;
import java.util.List;
/**
* 支持 BASIC AUTH和其他账户密码认证鉴权形式的Subject
* the subject support BASIC AUTH or other username-password AUTH
* @author tomsun28
* @date 12:42 2019-03-14
*/
......@@ -13,22 +13,22 @@ public class PasswordSubject implements Subject {
private static final long serialVersionUID = 1L;
/** 用户标识 **/
/** username **/
private String appId;
/** 账户密码 **/
/** password **/
private String password;
/** 访问用户的IP **/
/** remote IP **/
private String remoteHost;
/** 所拥有的角色 在解析完jwt之后把用户角色放到这里 **/
/** the roles which this user owned **/
private List<String> ownRoles;
/** 所访问资源地址 **/
/** the uri resource which this user want access **/
private String targetUri;
/** 所访问资源他支持的角色 **/
/** the Roles which can access this resource above-targetUri **/
private List<String> supportRoles;
......@@ -76,8 +76,8 @@ public class PasswordSubject implements Subject {
return new Builder(appId, password);
}
public static Builder builder(Subject auToken) {
return new Builder(auToken);
public static Builder builder(Subject subject) {
return new Builder(subject);
}
public static class Builder {
......@@ -95,12 +95,12 @@ public class PasswordSubject implements Subject {
}
@SuppressWarnings("unchecked")
public Builder(Subject auToken) {
this.appId = String.valueOf(auToken.getPrincipal());
this.password = String.valueOf(auToken.getCredentials());
this.ownRoles = (List<String>) auToken.getOwnRoles();
this.targetUri = String.valueOf(auToken.getTargetResource());
this.supportRoles = (List<String>) auToken.getSupportRoles();
public Builder(Subject subject) {
this.appId = String.valueOf(subject.getPrincipal());
this.password = String.valueOf(subject.getCredentials());
this.ownRoles = (List<String>) subject.getOwnRoles();
this.targetUri = String.valueOf(subject.getTargetResource());
this.supportRoles = (List<String>) subject.getSupportRoles();
}
public Builder setPrincipal(String appId) {
......
......@@ -5,6 +5,7 @@ import java.util.Collection;
import java.util.List;
/**
* subject summary
* @author tomsun28
* @date 22:03 2019-01-22
*/
......@@ -16,11 +17,11 @@ public class SurenessSubjectSum implements SubjectSum {
*/
private String principal;
/**
* 当前账户所拥有的角色
* the roles which this user owned
*/
private List<String> roles;
/**
* 当前账户这次请求他所请求的资源(即url===method)
* the uri resource which this user want access(url===method)
*/
private String targetResource;
......
package com.usthe.sureness.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
......@@ -48,6 +51,7 @@ public enum ClassScanner {
jar
}
private static final Logger log = LoggerFactory.getLogger(ClassScanner.class);
private static final Character STAR_CHAR = '*';
private static final String STAR_STR = "*";
......@@ -71,7 +75,7 @@ public enum ClassScanner {
}
/**
* Find all classes in packages 扫描一或多个包下的所有Class,包含接口类
* Find all classes in packages
*
* @param scanBasePackages package
* @return classes
......@@ -90,7 +94,7 @@ public enum ClassScanner {
}
/**
* Find all classes with given annotation in packages 扫描某个包下带有注解的Class
* Find all classes with given annotation in packages
*
* @param annotation annotation
* @param scanBasePackages package
......@@ -109,9 +113,9 @@ public enum ClassScanner {
}
/**
* Find all classes with given name patten 扫描某个包下所有类名匹配通配符的Class
* Find all classes with given name patten
*
* @param nameSimpleReg name patten, only 1 * allow, 类名简化版通配符,只允许一个星号出现
* @param nameSimpleReg name patten, only 1 * allow
* @param scanBasePackages scan package
* @return classes
*/
......@@ -127,7 +131,7 @@ public enum ClassScanner {
}
/**
* find all classes in one package 扫描某个包下所有Class类
* find all classes in one package
*
* @param pkg package
* @return Class
......@@ -135,21 +139,18 @@ public enum ClassScanner {
private static List<Class<?>> scanOnePackage(String pkg) {
List<Class<?>> classList = new LinkedList<>();
try {
// 包名转化为路径名
String pathName = package2Path(pkg);
// 获取路径下URL
Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(pathName);
// 循环扫描路径
classList = scanUrls(pkg, urls);
} catch (IOException e) {
System.err.println("Warning: Can not scan package:" + pkg);
log.error("Warning: Can not scan package:{}", pkg);
}
return classList;
}
/**
* find all classes in urls 扫描多个Url路径,找出符合包名的Class类
* find all classes in urls
*
* @param pkg package
* @param urls urls
......@@ -160,16 +161,13 @@ public enum ClassScanner {
List<Class<?>> classList = new LinkedList<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
// 获取协议
String protocol = url.getProtocol();
if (ProtocolTypes.file.name().equals(protocol)) {
// 文件
String path = URLDecoder.decode(url.getFile(), "UTF-8");
classList.addAll(recursiveScan4Path(pkg, path));
} else if (ProtocolTypes.jar.name().equals(protocol)) {
// jar包
String jarPath = getJarPathFormUrl(url);
classList.addAll(recursiveScan4Jar(pkg, jarPath));
}
......@@ -178,11 +176,8 @@ public enum ClassScanner {
}
/**
* get real path from url 从url中获取jar真实路径
* <p>
* jar文件url示例如下:
* <p>
* jar:file:/Users/cent/.gradle/caches/modules-2/files-2.1/org/lombok/1.18.4/7103ab51/lombok-1.18.4.jar!/org
* get real path from url
* eg: jar:file:/Users/cent/.gradle/caches/modules-2/files-2.1/org/lombok/1.18.4/7103ab51/lombok-1.18.4.jar!/org
*
* @param url url
* @return file
......@@ -193,11 +188,11 @@ public enum ClassScanner {
}
/**
* recursive scan for path 递归扫描指定文件路径下的Class文件
* recursive scan for path
*
* @param pkg package
* @param filePath path
* @return Class列表
* @return Class list
*/
private static List<Class<?>> recursiveScan4Path(String pkg, String filePath) {
List<Class<?>> classList = new LinkedList<>();
......@@ -207,7 +202,6 @@ public enum ClassScanner {
return classList;
}
// 处理类文件
File[] classes = file.listFiles(child -> isClass(child.getName()));
if (classes != null) {
for (File child : classes) {
......@@ -218,13 +212,12 @@ public enum ClassScanner {
Class<?> clz = Thread.currentThread().getContextClassLoader().loadClass(className);
classList.add(clz);
} catch (ClassNotFoundException | LinkageError e) {
System.err.println("Warning: Can not load class:" + className);
log.error("Warning: Can not load class: {}", className);
}
}
}
// 处理目录
File[] dirs = file.listFiles(File::isDirectory);
if (dirs != null) {
for (File child : dirs) {
......@@ -237,11 +230,11 @@ public enum ClassScanner {
}
/**
* Recursive scan 4 jar 递归扫描Jar文件内的Class类
* Recursive scan 4 jar
*
* @param pkg package
* @param jarPath jar path
* @return Class列表
* @return Class list
* @throws IOException when io error
*/
private static List<Class<?>> recursiveScan4Jar(String pkg, String jarPath) throws IOException {
......@@ -258,7 +251,6 @@ public enum ClassScanner {
}
if (isClass(name)) {
if (isAnonymousInnerClass(name)) {
// 是匿名内部类,跳过不作处理
continue;
}
......@@ -267,7 +259,7 @@ public enum ClassScanner {
Class<?> clz = Thread.currentThread().getContextClassLoader().loadClass(className);
classList.add(clz);
} catch (ClassNotFoundException | LinkageError e) {
System.err.println("Warning: Can not load class:" + className);
log.error("Warning: Can not load class: {}", className);
}
}
}
......
......@@ -11,14 +11,14 @@ import java.util.List;
import java.util.regex.Pattern;
/**
* json web token相关工具类
* json web token util
* use hmac algorithm, can change the secretKey by setDefaultSecretKey
* @author tomsun28
* @date 16:29 2018/3/8
*/
public class JsonWebTokenUtil {
/** 默认SUBJECT加密解密签名KEY **/
/** default SUBJECT KEY **/
private static final String DEFAULT_SECRET_KEY =
"MIIEowIBAl+f/dKhaX0csgOCTlCxq20yhmUea6H6JIpST3ST1SE2Rwp" +
"LnfKefTjsIfJLBa2YkhEqE/GtcHDTNe4CU6+9y/S5z50Kik70LsP43r" +
......@@ -28,14 +28,14 @@ public class JsonWebTokenUtil {
"CyaFv0bwq2Eik0jdrKUtsA6bx3sDJeFV643R+YYzGMRIqcBIp6AKA98" +
"GM2RIqcBIp6-?::4390fsf4sdl6opf)4ZI:tdQMtcQQ14pkOAQdQ546";
/** JWT格式3个点 **/
/** JWT format has 3 point **/
private static final int COUNT_3 = 3;
/** 判断是否是base64串 **/
/** Determine whether it is a base64 string **/
private static final Pattern BASE64_PATTERN =
Pattern.compile("^([A-Za-z0-9+/_-]+)(=*)$");
/** 加密解密签名 **/
/** Encryption and decryption signature **/
private static Key secretKey;
static {
......@@ -45,20 +45,19 @@ public class JsonWebTokenUtil {
/**
* json web token 签发
* @param id 令牌ID
* @param subject 用户ID
* @param issuer 签发人
* @param period 有效时间(毫秒)
* @param roles 访问主张-角色
* @param permissions 访问主张-权限
* @param isRefresh 是否是刷新token
* issue json web token
* @param id token ID
* @param subject user ID
* @param issuer issuer
* @param period period time(ms)
* @param roles Access claim-roles
* @param permissions Access claim-permissions
* @param isRefresh is a refresh token
* @return java.lang.String jwt
*/
public static String issueJwt(String id, String subject, String issuer, Long period,
List<String> roles, List<String> permissions,
Boolean isRefresh) {
// 当前时间戳
long currentTimeMillis = System.currentTimeMillis();
JwtBuilder jwtBuilder = Jwts.builder();
if (id != null) {
......@@ -70,9 +69,9 @@ public class JsonWebTokenUtil {
if (issuer != null) {
jwtBuilder.setIssuer(issuer);
}
// 设置签发时间
// set issue create time
jwtBuilder.setIssuedAt(new Date(currentTimeMillis));
// 设置到期时间
// set expired time
if (null != period) {
jwtBuilder.setExpiration(new Date(currentTimeMillis + period * 1000));
}
......@@ -85,17 +84,18 @@ public class JsonWebTokenUtil {
if (isRefresh != null) {
jwtBuilder.claim("isRefresh", isRefresh);
}
// 压缩,可选GZIP
// compress,optional GZIP
jwtBuilder.compressWith(CompressionCodecs.DEFLATE);
// 加密设置
// set secret key
jwtBuilder.signWith(secretKey);
return jwtBuilder.compact();
}
/**
* 判断其是否是JWT,这里主要用格式来判断,不校验
* To determine whether it is not a JWT
* Use format to judge, no verification
* @param jwt JWT TOKEN
* @return 为JWT返回false 否则 true
* @return is a JWT return false, else true
*/
public static boolean isNotJsonWebToken(String jwt) {
// base64url_encode(Header) + '.' + base64url_encode(Claims) + '.' + base64url_encode(Signature)
......@@ -114,12 +114,12 @@ public class JsonWebTokenUtil {
/**
*
* @param jwt json web token
* @return 解签实体
* @throws ExpiredJwtException token过期
* @throws UnsupportedJwtException 不支持的TOKEN
* @throws MalformedJwtException 参数格式形变等异常
* @throws SignatureException 签名异常
* @throws IllegalArgumentException 非法参数
* @return parse content body
* @throws ExpiredJwtException token expired
* @throws UnsupportedJwtException unSupport TOKEN
* @throws MalformedJwtException Parameter format exception
* @throws SignatureException signature exception
* @throws IllegalArgumentException illegal argument
*/
public static Claims parseJwt(String jwt) throws ExpiredJwtException, UnsupportedJwtException,
MalformedJwtException, SignatureException, IllegalArgumentException {
......@@ -127,18 +127,17 @@ public class JsonWebTokenUtil {
return Jwts.parserBuilder().setSigningKey(secretKey).build()
.parseClaimsJws(jwt).getBody();
// 令牌ID -- claims.getId()
// 客户标识 -- claims.getSubject()
// 客户标识
// 签发者 -- claims.getIssuer()
// 签发时间 -- claims.getIssuedAt()
// 接收方 -- claims.getAudience()
// 访问主张-角色 -- claims.get("roles", String.class)
// 访问主张-权限 -- claims.get("perms", String.class)
// token ID -- claims.getId()
// user ID -- claims.getSubject()
// issuer -- claims.getIssuer()
// issue time -- claims.getIssuedAt()
// audience -- claims.getAudience()
// Access claim-roles -- claims.get("roles", String.class)
// Access claim-permissions -- claims.get("perms", String.class)
}
/**
* 设置新的JWT加密解密签名
* set the jwt secret key
* @param secretNowKeyValue key value
*/
public static void setDefaultSecretKey(String secretNowKeyValue) {
......
......@@ -7,7 +7,7 @@ import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
/**
* md5 加密工具类
* md5 util
* @author tomsun28
* @date 20:48 2018/2/27
*/
......@@ -16,22 +16,16 @@ public class Md5Util {
private static final Logger logger = LoggerFactory.getLogger(Md5Util.class);
public static String md5(String content) {
// 用于加密的字符
// Characters used for encryption
char[] md5String = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
try {
// 使用平台默认的字符集将md5String编码为byte序列,并将结果存储到一个新的byte数组中
byte[] byteInput = content.getBytes(StandardCharsets.UTF_8);
// 信息摘要是安全的单向哈希函数,它接收任意大小的数据,并输出固定长度的哈希值
MessageDigest mdInst = MessageDigest.getInstance("MD5");
// MessageDigest对象通过使用update方法处理数据,使用指定的byte数组更新摘要
mdInst.update(byteInput);
//摘要更新后通过调用digest() 执行哈希计算,获得密文
// Perform hash calculation to obtain ciphertext
byte[] md = mdInst.digest();
//把密文转换成16进制的字符串形式
//Convert ciphertext into hexadecimal string form
int j = md.length;
char[] str = new char[j*2];
int k = 0;
......
......@@ -6,7 +6,7 @@ import javax.ws.rs.container.ContainerRequestContext;
import java.util.Random;
/**
* 一些公共处理工具类
* common util
* @author tomsun28
* @date 19:07 2019-03-09
*/
......@@ -70,13 +70,13 @@ public class SurenessCommonUtil {
/**
* 获取指定位数的随机字符串
* get random string
*
* @param length 长度
* @return 随机字符串
* @param length string length
* @return random string
*/
public static String getRandomString(int length) {
// 默认6位
// default length is 6
if (length < 1) {
length = 6;
}
......
......@@ -9,7 +9,7 @@ import java.util.HashMap;
import java.util.Map;
/**
* learn from ThreadContext
* learn from shiro ThreadContext
* @author from shiro
* @date 23:01 2019-01-09
*/
......@@ -23,7 +23,7 @@ public class SurenessContextHolder {
.withInitial(() -> new HashMap<>(8));
/**
* 线程结束前调用 清空内容 防止oom
* Called before the thread ends
*/
public static void clear() {
if (RESOURCES.get() != null) {
......
package com.usthe.sureness.matcher;
import com.usthe.sureness.matcher.util.TirePathTree;
import com.usthe.sureness.subject.Subject;
import com.usthe.sureness.subject.SubjectCreate;
import com.usthe.sureness.subject.SubjectFactory;
import com.usthe.sureness.subject.support.NoneSubject;
import com.usthe.sureness.subject.support.PasswordSubject;
import org.junit.AfterClass;
......
......@@ -31,12 +31,12 @@ public class TirePathTreeTest {
@Test
public void buildTree() {
Set<String> paths = new HashSet<>();
// 多'/'路径
// '/' path
paths.add("/api///v2////book///node//===get===[]");
// 配置不会覆盖,也不会叠加
// The configuration will not be overwritten or superimposed
paths.add("/api/v2/host===get===[role2]");
paths.add("/api/v2/host===get===[role2,role3]");
// 多种请求方式
// multi request method
paths.add("/api/v2/host===post===[role1]");
paths.add("/api/v2/host===delete===[role2,role3]");
paths.add("/api/v2/host===put===[role3,role4]");
......@@ -44,16 +44,16 @@ public class TirePathTreeTest {
paths.add("/api/v3/host===put===[role2,role3,role4]");
paths.add("/api/v2/detail===put===[role2,role3,role4]");
paths.add("/api/v2/mom===put===[role2,role3,role4]");
// *匹配
// match *
paths.add("/api/*/ha/*===put===[role2,role4]");
// 普通优先级>*
// priority: equals normal path > match *
paths.add("/api/v4/mom/ha===put===[role3,role4]");
paths.add("/api/*/mom/ha===put===[role2,role4]");
// **匹配
//match **
paths.add("/api/mi/**===put===[role5]");
paths.add("/api/mo/**/day===get===[role6]");
paths.add("/api/day/**/day/mo===put===[role7]");
// 普通优先级>*>**
// priority: equals normal path > match * > match **
paths.add("/api/v5/day/book===put===[role5]");
paths.add("/api/v5/**===put===[role6]");
paths.add("/api/demo/book/*/egg===get===[role1]");
......@@ -68,26 +68,26 @@ public class TirePathTreeTest {
@Test
public void searchPathFilterRoles() {
buildTree();
// 多'/'路径
// multi path '/'
Assert.assertEquals("[]", root.searchPathFilterRoles("/api/v2/book/node//===get"));
// 配置不会覆盖,也不会叠加
// The configuration will not be overwritten or superimposed
Assert.assertEquals("[role2]", root.searchPathFilterRoles("/api/v2/host===get"));
// 多种请求方式
// multi request method
Assert.assertEquals("[role1]", root.searchPathFilterRoles("/api/v2/host===post"));
Assert.assertEquals("[role2,role3]", root.searchPathFilterRoles("/api/v2/host===delete"));
Assert.assertEquals("[role3,role4]", root.searchPathFilterRoles("/api/v2/host===put"));
Assert.assertEquals("[role2,role3,role4]", root.searchPathFilterRoles("/api/v1/host===put"));
Assert.assertEquals("[role2,role3,role4]", root.searchPathFilterRoles("/api/v3/host===put"));
// *匹配
// match *
Assert.assertEquals("[role2,role4]", root.searchPathFilterRoles("/api/v2/ha/host===put"));
// 普通优先级>*
// priority: equals normal path > match *
Assert.assertEquals("[role3,role4]", root.searchPathFilterRoles("/api/v4/mom/ha===put"));
Assert.assertEquals("[role2,role4]", root.searchPathFilterRoles("/api/v6/mom/ha===put"));
// **匹配
// match **
Assert.assertEquals("[role5]", root.searchPathFilterRoles("/api/mi/tom/hello===put"));
Assert.assertEquals("[role6]", root.searchPathFilterRoles("/api/mo/tom/hello/day/day===get"));
Assert.assertEquals("[role7]", root.searchPathFilterRoles("/api/day/day/day/day/book/day/mo===put"));
// 普通优先级>*>**
// priority: equals normal path > match * > match **
Assert.assertEquals("[role5]", root.searchPathFilterRoles("/api/v5/day/book===put"));
Assert.assertEquals("[role1]", root.searchPathFilterRoles("/api/demo/book/tom/egg===get"));
Assert.assertEquals("[role2]", root.searchPathFilterRoles("/api/demo/book/tom/good/egg===get"));
......
......@@ -94,7 +94,6 @@
</execution>
</executions>
<dependencies>
<!-- 需要使用阿里的一些xml文件,因此需要这里增加p3c的依赖 -->
<dependency>
<groupId>com.alibaba.p3c</groupId>
<artifactId>p3c-pmd</artifactId>
......@@ -102,7 +101,7 @@
</dependency>
</dependencies>
</plugin>
<!-- compile setting 配置编译时的jdk version -->
<!-- compile setting jdk version -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
......
......@@ -38,7 +38,7 @@
<artifactId>sureness-core</artifactId>
</dependency>
<!-- lombok表达式 -->
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
......@@ -46,7 +46,7 @@
<scope>provided</scope>
</dependency>
<!-- java版本升级少包-->
<!-- java api-->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
......@@ -107,7 +107,6 @@
</execution>
</executions>
<dependencies>
<!-- 需要使用阿里的一些xml文件,因此需要这里增加p3c的依赖 -->
<dependency>
<groupId>com.alibaba.p3c</groupId>
<artifactId>p3c-pmd</artifactId>
......@@ -115,7 +114,7 @@
</dependency>
</dependencies>
</plugin>
<!-- java doc 生成 -->
<!-- java doc -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
......
......@@ -21,7 +21,7 @@ import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* 程序的http request请求入口过滤类示例 所有request请求都需经过此类
* sureness filter class example, filter all http request
* @author tomsun28
* @date 17:22 2019-05-12
*/
......@@ -29,7 +29,7 @@ import java.io.IOException;
@WebFilter(filterName = "SurenessFilterExample", urlPatterns = "/*", asyncSupported = true)
public class SurenessFilterExample implements Filter {
/** 日志操作 **/
/** logger **/
private static final Logger logger = LoggerFactory.getLogger(SurenessFilterExample.class);
@Override
......@@ -48,7 +48,8 @@ public class SurenessFilterExample implements Filter {
try {
SubjectSum subject = SurenessSecurityManager.getInstance().checkIn(servletRequest);
// 可以考虑使用SurenessContextHolder放入threadLocal中绑定
// You can consider using SurenessContextHolder to bind subject in threadLocal
// if bind, please remove it when end
if (subject != null) {
SurenessContextHolder.bindSubject(subject);
}
......
......@@ -5,7 +5,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* sureness 配置,使用默认的DefaultSurenessConfig
* sureness config,Use DefaultSurenessConfig
* @author tomsun28
* @date 23:38 2019-05-12
*/
......@@ -13,7 +13,7 @@ import org.springframework.context.annotation.Configuration;
public class SurenessConfiguration {
/**
* 新建初始化sureness默认配置加入bean池
* new sureness default config bean
* @return default config bean
*/
@Bean
......
......@@ -5,7 +5,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* webSocket endpoint config, 为websocket请求做端点配置
* webSocket endpoint config
* @author tomsun28
* @date 22:52 2019-05-26
*/
......
......@@ -17,7 +17,7 @@ import java.util.Map;
import java.util.UUID;
/**
* 用户登录认证controller
* user auth controller
* @author tomsun28
* @date 13:11 2019-05-26
*/
......@@ -26,14 +26,14 @@ public class AccountController {
private static final String APP_ID = "appId";
/**
* 账户数据提供
* account data provider
*/
private SurenessAccountProvider accountProvider = new DocumentResourceDefaultProvider();
/**
* 登录,此提供一个用户登录获取jwt接口.方便用jwt测试其他接口
* @param requestBody 请求体
* @return 响应信息
* login, this provider a get jwt api, convenient to test other api with jwt
* @param requestBody request
* @return response
*
*/
@PostMapping("/api/v1/account/auth")
......@@ -56,10 +56,10 @@ public class AccountController {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}
}
// issue jwt
// 获取其对应所拥有的角色(这里设计为角色对应资源,没有权限对应资源)
// Get the roles the user has - rbac
List<String> roles = account.getOwnRoles();
long refreshPeriodTime = 36000L;
// issue jwt
String jwt = JsonWebTokenUtil.issueJwt(UUID.randomUUID().toString(), appId,
"token-server", refreshPeriodTime >> 1, roles,
null, Boolean.FALSE);
......
......@@ -18,7 +18,7 @@ import java.util.Map;
import java.util.Objects;
/**
* 模拟资源controller,供测试调用
* simulate api controller, for testing
* @author tomsun28
* @date 17:35 2019-05-12
*/
......@@ -191,9 +191,9 @@ public class SimulateController {
}
/**
* 获取MOCK固定的返回数据MAP
* @param request http 请求
* @return 返回数据
* get the response map data from request
* @param request http request
* @return map data
*/
private Map<String, String> getResponseMap(HttpServletRequest request) {
StringBuilder builder = new StringBuilder();
......
......@@ -12,7 +12,7 @@ import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
/**
* webSocket资源模拟示例,供websocket测试
* websocket simulate api, for testing websocket
* @author tomsun28
* @date 22:21 2019-05-26
*/
......
......@@ -11,25 +11,24 @@ import java.io.IOException;
import java.io.PrintWriter;
/**
* 工具类
* util
* @author tomsun28
* @date 17:37 2019-05-12
*/
public class CommonUtil {
/** 日志操作 **/
/** logger **/
private static final Logger logger = LoggerFactory.getLogger(CommonUtil.class);
/** 访问资源成功的信息 **/
/** access success message **/
public static final String SUCCESS_ACCESS_RESOURCE = "access this resource: %s success";
/** 访问资源失败的信息 **/
/** access failed message **/
public static final String DENIED_ACCESS_RESOURCE = "access this resource: %s denied";
/**
* description 封装response 统一json返回
*
* @param content 内容
* write response json data
* @param content content
* @param response response
*/
public static void responseWrite(ResponseEntity content, ServletResponse response) {
......
......@@ -6,7 +6,7 @@ import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* Spring的ApplicationContext的持有者,可以用静态方法的方式获取spring容器中的bean
* spring context holder, can get bean from here
* @author tomsun28
* @date 21:07 2018/4/18
*/
......@@ -42,7 +42,7 @@ public class SpringContextHolder implements ApplicationContextAware {
private static void assertApplicationContext() {
if (null == SpringContextHolder.applicationContext) {
throw new RuntimeException("applicationContext为空,请检查是否注入springContextHolder");
throw new RuntimeException("applicationContext is null, please check if injected springContextHolder");
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true">
<!-- 日志输出上下文名称 -->
<contextName>sureness</contextName>
<!-- 输出日志到控制台 ConsoleAppender -->
<appender name="ConsoleAppender" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!--<pattern>%d %p (%file:%line\)- %m%n</pattern>-->
<!--格式化输出:%d:表示日期 %thread:表示线程名 %-5level:级别从左显示5个字符宽度 %msg:日志消息 %n:是换行符-->
<pattern>1-%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 输出日志到文件 每天一个文件 -->
<!--输出每天的运行日志到文件SystemOut.log-->
<appender name="SystemOutFileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>/opt/tomcat/logs/sureness/SystemOut.log</file>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 归档的日志文件的路径。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
<fileNamePattern>/opt/tomcat/logs/sureness/sys_bak/SystemOut-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 除按日志记录之外,还配置了日志文件不能超过2M,若超过2M,日志文件会以索引0开始 -->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>2MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 追加方式记录日志 -->
<append>true</append>
<!-- 日志文件的格式 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
<!-- 此日志文件记录debug及以上级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>debug</level>
<onMatch>ACCEPT</onMatch>
......@@ -42,68 +29,6 @@
</filter>
</appender>
<!-- 输出日志到文件 每天一个文件 -->
<!--输出每天的运行日志到文件SystemErrOut.log-->
<appender name="ErrOutFileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>/opt/tomcat/logs/sureness/SystemErrOut.log</file>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 归档的日志文件的路径。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
<fileNamePattern>/opt/tomcat/logs/sureness/err_bak/SystemErrOut-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 除按日志记录之外,还配置了日志文件不能超过2M,若超过2M,日志文件会以索引0开始 -->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>2MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 追加方式记录日志 -->
<append>true</append>
<!-- 日志文件的格式 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
<!-- 此日志文件记录error及以上级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>error</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 输出日志到文件 文件大小到达指定尺寸的时候文件会自动回滚 -->
<!-- 输出运行的SQL语句日志到文件SqlOut.log -->
<appender name="SqlOutFileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>/opt/tomcat/logs/sureness/SystemSqlOut.log</file>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 归档的日志文件的路径。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
<fileNamePattern>/opt/tomcat/logs/sureness/sql_bak/SystemSqlOut-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 除按日志记录之外,还配置了日志文件不能超过2M,若超过2M,日志文件会以索引0开始 -->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>2MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 追加方式记录日志 -->
<append>true</append>
<!-- 日志文件的格式 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
<!-- 此日志文件记录sql trace -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>debug</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!--这个logger的设置是:举例在org.springframework包下面的所有输出日志必须级别level在info及以上级别才会被输出!-->
<!--这样可以避免输出一些spring框架的许多常见debug信息!-->
<logger name="org.springframework" level="debug"/>
<logger name="org.springframework.boot.autoconfigure" level="info"/>
<logger name="org.json" level="error"/>
......@@ -112,39 +37,13 @@
<logger name="ch.qos.logback" level="info"/>
<!-- 生产环境配置文件 -->
<springProfile name="prod">
<!-- 下面是打印 mybatis sql语句日志的配置 -->
<!--<logger name="com.usthe.bootshiro.dao">-->
<!--<level value="debug"/>-->
<!--<appender-ref ref="SqlOutFileAppender"/>-->
<!--</logger>-->
<root level="DEBUG">
<appender-ref ref="ErrOutFileAppender"/>
<appender-ref ref="SystemOutFileAppender"/>
<appender-ref ref="ConsoleAppender"/>
</root>
</springProfile>
<!-- 测试环境配置文件 -->
<springProfile name="test">
<!-- 下面是打印 mybatis sql语句日志的配置 -->
<!--<logger name="com.usthe.bootshiro.dao">-->
<!--<level value="debug"/>-->
<!--<appender-ref ref="SqlOutFileAppender"/>-->
<!--</logger>-->
<root level="DEBUG">
<appender-ref ref="ErrOutFileAppender"/>
<appender-ref ref="SystemOutFileAppender"/>
<appender-ref ref="ConsoleAppender"/>
</root>
</springProfile>
<!--开发环境配置文件-->
<springProfile name="dev">
<root level="DEBUG">
<appender-ref ref="ConsoleAppender"/>
......
......@@ -51,7 +51,7 @@
<artifactId>sureness-core</artifactId>
</dependency>
<!-- lombok表达式 -->
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
......@@ -59,14 +59,14 @@
<scope>provided</scope>
</dependency>
<!--明文配置密码加密解密-->
<!--datasource passwd encrypt-->
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<!-- java版本升级少包-->
<!-- java api-->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
......@@ -140,7 +140,6 @@
</execution>
</executions>
<dependencies>
<!-- 需要使用阿里的一些xml文件,因此需要这里增加p3c的依赖 -->
<dependency>
<groupId>com.alibaba.p3c</groupId>
<artifactId>p3c-pmd</artifactId>
......@@ -148,7 +147,7 @@
</dependency>
</dependencies>
</plugin>
<!-- java doc 生成 -->
<!-- java doc -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
......
......@@ -79,7 +79,7 @@ public class ResourceController {
@GetMapping("/{currentPage}/{pageSize}")
public ResponseEntity<Message> getResource(@PathVariable Integer currentPage, @PathVariable Integer pageSize ) {
if (Objects.isNull(currentPage) || Objects.isNull(pageSize)) {
// 不分页,查询总
// no pageable
Optional<List<AuthResourceDO>> resourceListOptional = resourceService.getAllResource();
if (resourceListOptional.isPresent()) {
Message message = Message.builder().data(resourceListOptional.get()).build();
......@@ -89,7 +89,7 @@ public class ResourceController {
return ResponseEntity.ok().body(message);
}
} else {
// 分页查询
// pageable
Page<AuthResourceDO> resourcePage = resourceService.getPageResource(currentPage, pageSize);
Message message = Message.builder().data(resourcePage.get()).build();
return ResponseEntity.ok().body(message);
......
......@@ -111,7 +111,7 @@ public class RoleController {
@GetMapping("/{currentPage}/{pageSize}")
public ResponseEntity<Message> getRole(@PathVariable Integer currentPage, @PathVariable Integer pageSize ) {
if (Objects.isNull(currentPage) || Objects.isNull(pageSize)) {
// 不分页,查询总
// no pageable
Optional<List<AuthRoleDO>> roleListOptional = roleService.getAllRole();
if (roleListOptional.isPresent()) {
Message message = Message.builder().data(roleListOptional.get()).build();
......@@ -121,7 +121,7 @@ public class RoleController {
return ResponseEntity.ok().body(message);
}
} else {
// 分页查询
// pageable
Page<AuthRoleDO> rolePage = roleService.getPageRole(currentPage, pageSize);
Message message = Message.builder().data(rolePage).build();
return ResponseEntity.ok().body(message);
......
......@@ -17,8 +17,8 @@ import java.util.Optional;
public interface AuthResourceDao extends JpaRepository<AuthResourceDO, Long> {
/**
* 获取uri资源与其对应角色关系链 eg: /api/v2/host===post===[role2,role3,role4]
* @return 资源角色链set
* Get uri resource and resource-role relationship chain, eg: /api/v2/host===post===[role2,role3,role4]
* @return resource-role chain set
*/
@Query(value = "SELECT CONCAT(LOWER(res.uri),\"===\",LOWER(res.method),\"===[\",IFNULL(GROUP_CONCAT(DISTINCT role.code),\"\"),\"]\") " +
"FROM auth_resource res " +
......@@ -31,16 +31,16 @@ public interface AuthResourceDao extends JpaRepository<AuthResourceDO, Long> {
/**
* 获取禁用的uri资源 eg: /api/v2/host===post
* @return 资源链set
* Get disabled uri resources eg: /api/v2/host===post
* @return resouce set
*/
@Query("select CONCAT(LOWER(resource.uri),'===', resource.method) " +
"from AuthResourceDO resource where resource.status = 9 order by resource.id")
Optional<List<String>> getDisableResourcePathData();
/**
* 获取分页形式的当前角色拥有的可用API资源
* @param roleId 角色ID
* Get the available API resources owned by the current role in the form of paging
* @param roleId roleId
* @param request page
* @return api resource list
*/
......
......@@ -14,9 +14,9 @@ import java.util.List;
public interface AuthRoleDao extends JpaRepository<AuthRoleDO, Long> {
/**
* 查询当前用户所拥有的角色
* @param username 账户名称
* @return 角色list
* Query the role owned by the current user
* @param username username
* @return role list
*/
@Query("select ar.name from AuthRoleDO ar, AuthUserDO au, AuthUserRoleBindDO bind " +
"where ar.id = bind.roleId and au.id = bind.userId and au.username = :username")
......
......@@ -16,9 +16,9 @@ import java.util.List;
public interface AuthRoleResourceBindDao extends JpaRepository<AuthRoleResourceBindDO, Long> {
/**
* 查询当前角色拥有的资源
* @param roleId 角色ID
* @return 资源list
* Query the resources owned by the current role
* @param roleId roleId
* @return resource list
*/
@Query("select rs from AuthResourceDO rs, AuthRoleResourceBindDO bind " +
"where rs.id = bind.resourceId and bind.roleId = :roleId")
......
......@@ -15,17 +15,17 @@ import java.util.Optional;
public interface AuthUserDao extends JpaRepository<AuthUserDO, Long> {
/**
* 通过username获取对应user
* @param username 账户名称
* Get user by username
* @param username username
* @return user
*/
@Query("select au from AuthUserDO au where au.username = :username")
Optional<AuthUserDO> findAuthUserByUsername(@Param("username") String username);
/**
* 查询当前用户所拥有的角色
* @param username 账户名称
* @return 角色list
* Query the role owned by the current user
* @param username username
* @return role list
*/
@Query("select ar.code from AuthRoleDO ar, AuthUserDO au, AuthUserRoleBindDO bind " +
"where ar.id = bind.roleId and au.id = bind.userId and au.username = :username")
......
......@@ -15,9 +15,9 @@ import java.util.List;
public interface AuthUserRoleBindDao extends JpaRepository<AuthUserRoleBindDO, Long> {
/**
* 查询当前用户所拥有的角色
* @param userId 用户ID
* @return 角色list
* Query the role owned by the current user
* @param userId userId
* @return role list
*/
@Query("select ar from AuthRoleDO ar, AuthUserRoleBindDO bind " +
"where ar.id = bind.roleId and bind.userId = :userId")
......
......@@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* 全局controller异常捕获
* controller exception handler
* @author tomsun28
* @date 22:45 2019-08-01
*/
......@@ -21,9 +21,9 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
public class GlobalExceptionHandler {
/**
* 对于所有接口入参数据校验抛出的异常统一处理
* @param exception 入参数据校验异常
* @return 统一错误信息体
* handler the exception thrown for data input verify
* @param exception data input verify exception
* @return response
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
......@@ -41,9 +41,9 @@ public class GlobalExceptionHandler {
}
/**
* 对于所有数据库dao操作的异常统一处理
* @param exception 数据库异常
* @return 统一错误信息体
* handler the exception thrown for datastore error
* @param exception datastore exception
* @return response
*/
@ExceptionHandler(DataAccessException.class)
@ResponseBody
......@@ -58,9 +58,9 @@ public class GlobalExceptionHandler {
}
/**
* 对于请求数据和系统数据状态不一致异常统一处理
* @param exception 数据状态不一致异常
* @return 统一错误信息体
* handler the exception thrown for data conflict
* @param exception data conflict
* @return response
*/
@ExceptionHandler(DataConflictException.class)
@ResponseBody
......@@ -75,9 +75,9 @@ public class GlobalExceptionHandler {
}
/**
* 对所以未捕获未知异常统一处理
* handler the exception thrown for unCatch and unKnown
* @param exception UnknownException
* @return 统一错误信息体
* @return response
*/
@ExceptionHandler(Exception.class)
@ResponseBody
......
......@@ -6,7 +6,7 @@ import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 前后端http api统一消息定义协议 Message
* Unified message structure definition for front and back ends
*
* {
* data:{....},
......@@ -22,12 +22,12 @@ import lombok.NoArgsConstructor;
public class Message {
/**
* 消息内容 存储对象数据
* message body data
*/
private Object data;
/**
* 发生异常时信息
* exception message when error happen
*/
private String errorMsg;
......
......@@ -16,7 +16,7 @@ import javax.validation.constraints.NotBlank;
import java.time.LocalDateTime;
/**
* 资源实体
* resource entity
* @author tomsun28
* @date 00:00 2019-07-26
*/
......
......@@ -16,7 +16,7 @@ import javax.validation.constraints.NotBlank;
import java.time.LocalDateTime;
/**
* 角色实体
* role entity
* @author tomsun28
* @date 00:27 2019-07-27
*/
......
......@@ -15,7 +15,7 @@ import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
/**
* 资源与角色映射实体
* resource-role mapping entity
* @author tomsun28
* @date 00:28 2019-07-27
*/
......
......@@ -16,7 +16,7 @@ import javax.validation.constraints.NotBlank;
import java.time.LocalDateTime;
/**
* 用户实体
* user entity
* @author tomsun28
* @date 00:29 2019-07-27
*/
......
......@@ -14,7 +14,7 @@ import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
/**
* 用户与角色映射实体
* user-role mapping entity
* @author tomsun28
* @date 00:30 2019-07-27
*/
......
......@@ -11,36 +11,36 @@ import java.util.List;
*/
public interface AccountService {
/**
* 认证账户有效性 账户名称密码
* @param account 账户内容
* @return 成功true 失败false
* Verify account validity, username and password
* @param account account info
* @return success-true failed-false
*/
boolean authenticateAccount(Account account);
/**
* 获取对应username账户所拥有的所有角色,组成字符串
* @param username 账户名称
* @return 角色拼接字符串 eg role1,role3,role2
* Get all roles owned by this username account, combine them into string list
* @param username account username
* @return role-string eg role1,role3,role2
*/
List<String> loadAccountRoles(String username);
/**
* 注册账户
* @param account 简单的账户密码注册
* @return 注册成功返回true 失败false
* register account
* @param account account info
* @return success-true failed-false
*/
boolean registerAccount(Account account);
/**
* 判断账户是否已经存在
* @param account 账户信息
* @return 存在true 不存在false
* Determine whether the account already exists
* @param account account info
* @return exist-true no-false
*/
boolean isAccountExist(Account account);
/**
* 通过username加载对于的account信息
* @param username 账户名
* Load the account information by username
* @param username account username
* @return account
*/
SurenessAccount loadAccount(String username);
......
......@@ -14,56 +14,56 @@ import java.util.Set;
public interface ResourceService {
/**
* 增加uri资源
* @param authResource 资源
* @return 增加成功true 失败false
* add uri resource
* @param authResource resource
* @return success-true failed-false
*/
boolean addResource(AuthResourceDO authResource);
/**
* 判断此资源是否已经存在
* @param authResource 资源
* @return 已经存在true 不存在false
* Determine whether the resource already exists
* @param authResource resource
* @return existed-true no-false
*/
boolean isResourceExist(AuthResourceDO authResource);
/**
* 更新uri资源
* @param authResource 资源
* @return 更新成功true 失败false
* update uri resource
* @param authResource resource
* @return success-true failed-false
*/
boolean updateResource(AuthResourceDO authResource);
/**
* 删除指定uri资源
* @param resourceId 资源ID
* @return 删除成功true 不存在false
* delete uri resource
* @param resourceId resource ID
* @return success-true no existed-false
*/
boolean deleteResource(Long resourceId);
/**
* 获取所有资源
* @return 资源list
* get all resources
* @return resource list
*/
Optional<List<AuthResourceDO>> getAllResource();
/**
* 获取分页的资源页
* @param currentPage 当前页
* @param pageSize 页大小
* @return 资源的分页
* get resource by page
* @param currentPage current page
* @param pageSize page size
* @return Page of resource
*/
Page<AuthResourceDO> getPageResource(Integer currentPage, Integer pageSize);
/**
* 获取有效的资源路径角色
* @return 资源路径角色
* get enabled resource-path-role eg: /api/v2/host===post===[role2,role3,role4]
* @return resource-path-role
*/
Set<String> getAllEnableResourcePath();
/**
* 获取无效的资源路径
* @return 资源路径
* get disable resource-path-role eg: /api/v2/host===post===[role2,role3,role4]
* @return resource-path-role
*/
Set<String> getAllDisableResourcePath();
}
......@@ -14,67 +14,67 @@ import java.util.Optional;
public interface RoleService {
/**
* 判断此角色是否存在
* @param authRole 角色
* @return 已存在true 不存在false
* Determine whether the role already exists
* @param authRole role
* @return existed-true no-false
*/
boolean isRoleExist(AuthRoleDO authRole);
/**
* 增加角色
* @param authRole 角色
* @return 增加成功true 失败false
* add role
* @param authRole role
* @return add success-true failed-false
*/
boolean addRole(AuthRoleDO authRole);
/**
* 更新角色
* @param authRole 角色
* @return 更新成功返回true 失败false
* update role
* @param authRole role
* @return success-true failed-false
*/
boolean updateRole(AuthRoleDO authRole);
/**
* 删除角色
* @param roleId 角色ID
* @return 删除成功true 不存在失败false
* delete role
* @param roleId role ID
* @return success-true failed-false
*/
boolean deleteRole(Long roleId);
/**
* 获取所有角色
* @return 角色list
* get all role list
* @return role list
*/
Optional<List<AuthRoleDO>> getAllRole();
/**
* 获取角色的分页
* @param currentPage 当前页码
* @param pageSize 页大小
* @return 角色的分页
* get roles page
* @param currentPage current page
* @param pageSize page size
* @return Page of roles
*/
Page<AuthRoleDO> getPageRole(Integer currentPage, Integer pageSize);
/**
* 获取角色所拥有API资源的分页
* @param roleId 角色ID
* @param currentPage 当前页码
* @param pageSize 页大小
* @return 角色的分页
* get pageable resources which this role owned
* @param roleId role ID
* @param currentPage current page
* @param pageSize page size
* @return Page of resources
*/
Page<AuthResourceDO> getPageResourceOwnRole(Long roleId, Integer currentPage, Integer pageSize);
/**
* 将资源授权给角色
* @param roleId 角色ID
* @param resourceId 资源ID
* authority this resource to this role
* @param roleId role ID
* @param resourceId resource ID
*/
void authorityRoleResource(Long roleId, Long resourceId);
/**
* 删除授权给角色此资源
* @param roleId 角色ID
* @param resourceId 资源ID
* unAuthority this resource in this role
* @param roleId role ID
* @param resourceId resource ID
*/
void deleteAuthorityRoleResource(Long roleId, Long resourceId);
}
......@@ -39,7 +39,7 @@ public class AccountServiceImpl implements AccountService {
return false;
}
if (Objects.nonNull(authUser.getSalt())) {
// 用盐加密
// md5 with salt
password = Md5Util.md5(password + authUser.getSalt());
}
......
......@@ -2,7 +2,7 @@ package com.usthe.sureness.sample.tom.service.impl;
/**
* 请求操作数据与内部数据状态不一致异常
* data conflict exception
* @author tomsun28
* @date 22:55 2020-04-27
*/
......
......@@ -96,22 +96,22 @@ public class RoleServiceImpl implements RoleService {
@Override
public void authorityRoleResource(Long roleId, Long resourceId) {
// 判断此资源和角色是否存在
// Determine whether this resource and role exist
if (!authRoleDao.existsById(roleId) || !authResourceDao.existsById(resourceId)) {
throw new DataConflictException("roleId or resourceId not exist");
}
// 直接保存关联关系,若存在数据库唯一索引会起作用
// insert it in database, if existed the unique index will work
AuthRoleResourceBindDO bind = AuthRoleResourceBindDO
.builder().roleId(roleId).resourceId(resourceId).build();
roleResourceBindDao.saveAndFlush(bind);
// 刷新认证过滤链
// refresh resource path data tree
treePathRoleMatcher.rebuildTree();
}
@Override
public void deleteAuthorityRoleResource(Long roleId, Long resourceId) {
roleResourceBindDao.deleteRoleResourceBind(roleId, resourceId);
// 刷新认证过滤链
// refresh resource path data tree
treePathRoleMatcher.rebuildTree();
}
}
......@@ -32,7 +32,7 @@ import java.util.Collections;
import java.util.Map;
/**
* filter拦截请求 经sureness保护
* sureness filter class example, filter all http request
* @author tomsun28
* @date 23:22 2020-03-02
*/
......@@ -40,7 +40,7 @@ import java.util.Map;
@WebFilter(filterName = "SurenessFilterExample", urlPatterns = "/*", asyncSupported = true)
public class SurenessFilterExample implements Filter {
/** 日志操作 **/
/** logger **/
private static final Logger logger = LoggerFactory.getLogger(SurenessFilterExample.class);
@Override
......@@ -48,7 +48,8 @@ public class SurenessFilterExample implements Filter {
try {
SubjectSum subject = SurenessSecurityManager.getInstance().checkIn(servletRequest);
// 可以考虑使用SurenessContextHolder放入threadLocal中绑定
// You can consider using SurenessContextHolder to bind subject in threadLocal
// if bind, please remove it when end
if (subject != null) {
SurenessContextHolder.bindSubject(subject);
}
......@@ -93,9 +94,8 @@ public class SurenessFilterExample implements Filter {
}
/**
* description 封装response 统一json返回
*
* @param content 内容
* write response json data
* @param content content
* @param response response
*/
private void responseWrite(ResponseEntity<?> content, ServletResponse response) {
......
......@@ -30,12 +30,12 @@ public class CustomTokenProcessor extends BaseProcessor {
private SurenessAccountProvider accountProvider;
@Override
public boolean canSupportAuTokenClass(Class<?> var) {
public boolean canSupportSubjectClass(Class<?> var) {
return var == CustomTokenSubject.class;
}
@Override
public Class<?> getSupportAuTokenClass() {
public Class<?> getSupportSubjectClass() {
return CustomTokenSubject.class;
}
......
......@@ -7,6 +7,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* the provider provides account info
* load account info from database
* @author tomsun28
* @date 22:44 2020-03-02
*/
......
package com.usthe.sureness.sample.tom.sureness.provider;
import com.usthe.sureness.matcher.PathTreeProvider;
import com.usthe.sureness.provider.SurenessAccount;
import com.usthe.sureness.provider.SurenessAccountProvider;
import com.usthe.sureness.sample.tom.dao.AuthResourceDao;
import com.usthe.sureness.sample.tom.service.ResourceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.Set;
/**
* 从数据库加载资源配置信息和账户信息提供者
* ths provider provides path resources
* load sureness config resource form database
* @author tomsun28
* @date 16:00 2019-08-04
*/
......
......@@ -7,15 +7,15 @@ import com.usthe.sureness.subject.support.PasswordSubject;
import javax.servlet.http.HttpServletRequest;
/**
* 自定义的subject creator
* 这里演示一个自定义的creator
* 我们平时账户密码认证除了basic auth方式之外
* 可能会自定义从其他地方获取我们的账户密码来认证 eg: header的username字段作为账号,password字段作为密码
* header {
* custom subject creator
* A custom creator is demonstrated here
* In addition to the basic auth method, we may obtain our account password from other places for authentication.
* eg: username and password in header
* header {
* "username": "userTom",
* "password": "123456"
* }
* 我们自定义一个creator 从header上面取出信息创建PasswordSubject
* Here we define a creator to create PasswordSubject from this request header like above.
* @author tomsun28
* @date 22:59 2020-03-02
*/
......@@ -26,7 +26,7 @@ public class CustomPasswdSubjectCreator implements SubjectCreate {
@Override
public boolean canSupportSubject(Object context) {
// 定义什么样的请求信息才能被CustomSubjectCreator创建subject
// define which request can be access
if (context instanceof HttpServletRequest) {
String username = ((HttpServletRequest)context).getHeader(USERNAME);
String password = ((HttpServletRequest)context).getHeader(PASSWORD);
......@@ -38,7 +38,7 @@ public class CustomPasswdSubjectCreator implements SubjectCreate {
@Override
public Subject createSubject(Object context) {
// 创建PasswordSubject
// create PasswordSubject from request
String username = ((HttpServletRequest)context).getHeader(USERNAME);
String password = ((HttpServletRequest)context).getHeader(PASSWORD);
......
......@@ -13,25 +13,25 @@ public class CustomTokenSubject implements Subject {
private static final long serialVersionUID = 1L;
/** 用户的标识 **/
/** user identifier **/
private String appId;
/** token : admin--issueTime--refreshPeriodTime--uuid **/
private String token;
/** 访问用户的IP **/
/** remote ip **/
private String remoteHost;
/** 访问用户的设备信息 **/
/** remote device **/
private String userAgent;
/** 所拥有的角色 在解析完jwt之后把用户角色放到这里 **/
/** the roles which this user owned **/
private List<String> ownRoles;
/** 所访问资源地址 **/
/** the uri resource which this user want access **/
private String targetUri;
/** 所访问资源他支持的角色 **/
/** the Roles which can access this resource above-targetUri **/
private List<String> supportRoles;
private CustomTokenSubject(Builder builder) {
......@@ -87,8 +87,8 @@ public class CustomTokenSubject implements Subject {
return new Builder(token);
}
public static Builder builder(Subject auToken) {
return new Builder(auToken);
public static Builder builder(Subject subject) {
return new Builder(subject);
}
public static class Builder {
......@@ -106,12 +106,12 @@ public class CustomTokenSubject implements Subject {
}
@SuppressWarnings("unchecked")
public Builder(Subject auToken) {
this.appId = String.valueOf(auToken.getPrincipal());
this.token = String.valueOf(auToken.getCredentials());
this.ownRoles = (List<String>) auToken.getOwnRoles();
this.targetUri = String.valueOf(auToken.getTargetResource());
this.supportRoles = (List<String>) auToken.getSupportRoles();
public Builder(Subject subject) {
this.appId = String.valueOf(subject.getPrincipal());
this.token = String.valueOf(subject.getCredentials());
this.ownRoles = (List<String>) subject.getOwnRoles();
this.targetUri = String.valueOf(subject.getTargetResource());
this.supportRoles = (List<String>) subject.getSupportRoles();
}
public Builder setPrincipal(String appId) {
......
......@@ -9,7 +9,6 @@ jasypt:
password: e!swhdg&d763jo
---
# 开发环境配置(配置项只包括环境不同项)
spring:
profiles: dev
datasource:
......@@ -21,13 +20,14 @@ spring:
schema: classpath:db/schema.sql
data: classpath:db/data.sql
# 每次重启都会根据data.sql schema.sql重建表数据, 设置 NEVER 就不启动重建
# Each restart will rebuild the table data according to data.sql schema.sql
# setting NEVER will not start the reconstruction
initialization-mode: always
jpa:
database: mysql
show-sql: true
---
# 开发环境配置(配置项只包括环境不同项)
spring:
profiles: prod
datasource:
......
......@@ -2,29 +2,29 @@ use tom ;
-- ----------------------------
-- Records of auth_resource
-- ----------------------------
insert into auth_resource (id, name, code, uri, type, method, status, description) values (101, '用户获取token', 'ACCOUNT_TOKEN', '/auth/token', 'account', 'POST', 9, null);
insert into auth_resource (id, name, code, uri, type, method, status, description) values (102, '用户注册', 'ACCOUNT_REGISTER', '/auth/register', 'account', 'POST', 9, null);
insert into auth_resource (id, name, code, uri, type, method, status, description) values (103, '新增资源', 'ADD_RESOURCE', '/resource', 'resource', 'POST', 1, null);
insert into auth_resource (id, name, code, uri, type, method, status, description) values (104, '更新资源', 'UPDATE_RESOURCE', '/resource', 'resource', 'PUT', 1, null);
insert into auth_resource (id, name, code, uri, type, method, status, description) values (105, '删除资源', 'DELETE_RESOURCE', '/resource/*', 'resource', 'DELETE', 1, null);
insert into auth_resource (id, name, code, uri, type, method, status, description) values (106, '获取资源', 'GET_RESOURCES', '/resource/*/*', 'resource', 'GET', 1, null);
insert into auth_resource (id, name, code, uri, type, method, status, description) values (107, '添加角色', 'ADD_ROLE', '/role', 'role', 'POST', 1, null);
insert into auth_resource (id, name, code, uri, type, method, status, description) values (108, '更新角色', 'UPDATE_ROLE', '/role', 'role', 'PUT', 1, null);
insert into auth_resource (id, name, code, uri, type, method, status, description) values (109, '删除角色', 'DELETE_ROLE', '/role/*', 'role', 'DELETE', 1, null);
insert into auth_resource (id, name, code, uri, type, method, status, description) values (110, '获取角色', 'GET_ROLES', '/role/*/*', 'role', 'GET', 1, null);
insert into auth_resource (id, name, code, uri, type, method, status, description) values (111, '用户获取custom token', 'ACCOUNT_CUSTOM_TOKEN', '/auth/custom/token', 'account', 'POST', 9, null);
insert into auth_resource (id, name, code, uri, type, method, status, description) values (101, 'User get token', 'ACCOUNT_TOKEN', '/auth/token', 'account', 'POST', 9, null);
insert into auth_resource (id, name, code, uri, type, method, status, description) values (102, 'User register', 'ACCOUNT_REGISTER', '/auth/register', 'account', 'POST', 9, null);
insert into auth_resource (id, name, code, uri, type, method, status, description) values (103, 'Add resource', 'ADD_RESOURCE', '/resource', 'resource', 'POST', 1, null);
insert into auth_resource (id, name, code, uri, type, method, status, description) values (104, 'Update resource', 'UPDATE_RESOURCE', '/resource', 'resource', 'PUT', 1, null);
insert into auth_resource (id, name, code, uri, type, method, status, description) values (105, 'Delete resource', 'DELETE_RESOURCE', '/resource/*', 'resource', 'DELETE', 1, null);
insert into auth_resource (id, name, code, uri, type, method, status, description) values (106, 'Get resource', 'GET_RESOURCES', '/resource/*/*', 'resource', 'GET', 1, null);
insert into auth_resource (id, name, code, uri, type, method, status, description) values (107, 'Add role', 'ADD_ROLE', '/role', 'role', 'POST', 1, null);
insert into auth_resource (id, name, code, uri, type, method, status, description) values (108, 'Update role', 'UPDATE_ROLE', '/role', 'role', 'PUT', 1, null);
insert into auth_resource (id, name, code, uri, type, method, status, description) values (109, 'Delete role', 'DELETE_ROLE', '/role/*', 'role', 'DELETE', 1, null);
insert into auth_resource (id, name, code, uri, type, method, status, description) values (110, 'Get role', 'GET_ROLES', '/role/*/*', 'role', 'GET', 1, null);
insert into auth_resource (id, name, code, uri, type, method, status, description) values (111, 'User get custom token', 'ACCOUNT_CUSTOM_TOKEN', '/auth/custom/token', 'account', 'POST', 9, null);
-- ----------------------------
-- Records of auth_role
-- ----------------------------
insert into auth_role (id, name, code, status, description) values (100, '管理员角色', 'role_admin', 1, null);
insert into auth_role (id, name, code, status, description) values (102, '用户角色', 'role_user', 1, null);
insert into auth_role (id, name, code, status, description) values (103, '访客角色', 'role_guest', 1, null);
insert into auth_role (id, name, code, status, description) values (100, 'admin role', 'role_admin', 1, null);
insert into auth_role (id, name, code, status, description) values (102, 'user role', 'role_user', 1, null);
insert into auth_role (id, name, code, status, description) values (103, 'guest role', 'role_guest', 1, null);
-- ----------------------------
-- Records of auth_role_resource_bind
-- ----------------------------
-- role_admin拥有所有资源
-- role_admin has these resource
insert into auth_role_resource_bind (id, role_id, resource_id) values (1, 100, 101);
insert into auth_role_resource_bind (id, role_id, resource_id) values (2, 100, 102);
insert into auth_role_resource_bind (id, role_id, resource_id) values (3, 100, 103);
......@@ -36,7 +36,7 @@ insert into auth_role_resource_bind (id, role_id, resource_id) values (8, 100, 1
insert into auth_role_resource_bind (id, role_id, resource_id) values (9, 100, 109);
insert into auth_role_resource_bind (id, role_id, resource_id) values (10, 100, 110);
-- role_user拥有查看新增修改资源,不拥有删除资源
-- role_user has "get,add,update" related resources, do not have "delete" related resources
insert into auth_role_resource_bind (id, role_id, resource_id) values (11, 102, 103);
insert into auth_role_resource_bind (id, role_id, resource_id) values (12, 102, 104);
insert into auth_role_resource_bind (id, role_id, resource_id) values (13, 102, 106);
......@@ -44,7 +44,7 @@ insert into auth_role_resource_bind (id, role_id, resource_id) values (14, 102,
insert into auth_role_resource_bind (id, role_id, resource_id) values (15, 102, 108);
insert into auth_role_resource_bind (id, role_id, resource_id) values (16, 102, 110);
-- role_guest拥有查看资源
-- role_guest has "get" related resources
insert into auth_role_resource_bind (id, role_id, resource_id) values (17, 103, 106);
insert into auth_role_resource_bind (id, role_id, resource_id) values (18, 103, 110);
......
......@@ -6,16 +6,16 @@ use tom;
DROP TABLE IF EXISTS auth_resource ;
CREATE TABLE auth_resource
(
id bigint not null auto_increment comment '资源ID',
name varchar(50) not null comment '资源名称',
code varchar(50) not null comment '资源编码',
uri varchar(255) not null comment '访问地址URL',
type varchar(20) comment '类型 资源的类别',
method varchar(10) not null comment '访问方式 GET POST PUT DELETE PATCH',
status smallint(4) not null default 1 comment '状态 1:正常、9:过滤(保护排除)',
description varchar(255) comment '资源描述',
gmt_create timestamp default current_timestamp comment '创建时间',
gmt_update datetime default current_timestamp on update current_timestamp comment '更新时间',
id bigint not null auto_increment comment 'resource ID',
name varchar(50) not null comment 'resource name',
code varchar(50) not null comment 'resource code',
uri varchar(255) not null comment 'access URL',
type varchar(20) comment 'resource type',
method varchar(10) not null comment 'access method: GET POST PUT DELETE PATCH',
status smallint(4) not null default 1 comment 'status 1:normal、9:filtering(Exclusion protection-all can access this api)',
description varchar(255) comment 'resource description',
gmt_create timestamp default current_timestamp comment 'create time',
gmt_update datetime default current_timestamp on update current_timestamp comment 'update time',
primary key (id)
) ENGINE = InnoDB DEFAULT CHARSET=utf8;
......@@ -25,13 +25,13 @@ CREATE TABLE auth_resource
DROP TABLE IF EXISTS auth_role ;
CREATE TABLE auth_role
(
id bigint not null auto_increment comment '角色ID',
name varchar(50) not null comment '角色名称',
code varchar(50) not null comment '角色编码',
status smallint(4) not null default 1 comment '状态 1:正常、9:禁用',
description varchar(255) comment '角色描述',
gmt_create timestamp default current_timestamp comment '创建时间',
gmt_update datetime default current_timestamp on update current_timestamp comment '更新时间',
id bigint not null auto_increment comment 'role ID',
name varchar(50) not null comment 'role name',
code varchar(50) not null comment 'role code',
status smallint(4) not null default 1 comment 'status 1:normal、9:disable',
description varchar(255) comment 'role description',
gmt_create timestamp default current_timestamp comment 'create time',
gmt_update datetime default current_timestamp on update current_timestamp comment 'update time',
primary key ( id )
) ENGINE = InnoDB DEFAULT CHARSET=utf8;
......@@ -41,11 +41,11 @@ CREATE TABLE auth_role
DROP TABLE IF EXISTS auth_role_resource_bind;
CREATE TABLE auth_role_resource_bind
(
id bigint not null auto_increment comment '主键ID',
role_id bigint not null comment '角色ID',
resource_id bigint not null comment '资源ID',
gmt_create timestamp default current_timestamp comment '创建时间',
gmt_update datetime default current_timestamp on update current_timestamp comment '更新时间',
id bigint not null auto_increment comment 'ID',
role_id bigint not null comment 'role ID',
resource_id bigint not null comment 'resource ID',
gmt_create timestamp default current_timestamp comment 'create time',
gmt_update datetime default current_timestamp on update current_timestamp comment 'update time',
primary key (id),
unique key unique_bind (role_id, resource_id)
) ENGINE = InnoDB DEFAULT CHARSET=utf8;
......@@ -56,18 +56,18 @@ CREATE TABLE auth_role_resource_bind
DROP TABLE IF EXISTS auth_user ;
CREATE TABLE auth_user
(
id bigint not null auto_increment comment '主键ID',
username varchar(50) not null comment '用户名(nick_name)',
password varchar(50) not null comment '密码(MD5(密码+盐))',
salt varchar(20) comment '',
avatar varchar(100) comment '头像',
phone varchar(20) comment '电话号码(唯一)',
email varchar(50) comment '邮件地址(唯一)',
sex tinyint(4) comment '性别(1.男 2.女)',
status tinyint(4) not null default 1 comment '账户状态(1.正常 2.锁定 3.删除 4.非法)',
create_where tinyint(4) comment '创建来源(1.web 2.android 3.ios 4.win 5.mac 6.linux)',
gmt_create timestamp default current_timestamp comment '创建时间',
gmt_update datetime default current_timestamp on update current_timestamp comment '更新时间',
id bigint not null auto_increment comment 'ID',
username varchar(50) not null comment 'username(nick_name)',
password varchar(50) not null comment 'password=MD5(passwd+salt)',
salt varchar(20) comment 'salt',
avatar varchar(100) comment 'avatar',
phone varchar(20) comment 'phone number(unique)',
email varchar(50) comment 'email(unique)',
sex tinyint(4) comment 'sex(1.man 2.woman)',
status tinyint(4) not null default 1 comment 'account status(1.normal 2.locked 3.deleted 4.illegal)',
create_where tinyint(4) comment 'create where(1.web 2.android 3.ios 4.win 5.mac 6.linux)',
gmt_create timestamp default current_timestamp comment 'create time',
gmt_update datetime default current_timestamp on update current_timestamp comment 'update time',
primary key (id),
unique (username, phone, email)
) ENGINE = InnoDB DEFAULT CHARSET=utf8;
......@@ -78,11 +78,11 @@ CREATE TABLE auth_user
DROP TABLE IF EXISTS auth_user_role_bind ;
CREATE TABLE auth_user_role_bind
(
id bigint not null auto_increment comment '主键ID',
user_id bigint not null comment '用户ID',
role_id bigint not null comment '角色ID',
gmt_create timestamp default current_timestamp comment '创建时间',
gmt_update datetime default current_timestamp on update current_timestamp comment '更新时间',
id bigint not null auto_increment comment 'ID',
user_id bigint not null comment 'user ID',
role_id bigint not null comment 'role ID',
gmt_create timestamp default current_timestamp comment 'create time',
gmt_update datetime default current_timestamp on update current_timestamp comment 'update time',
primary key (id),
unique key unique_bind (user_id, role_id)
) ENGINE = InnoDB DEFAULT CHARSET=utf8;
\ No newline at end of file
......@@ -17,18 +17,18 @@ import java.util.Optional;
* @author tomsun28
* @date 22:35 2019-07-27
*/
@DisplayName("数据库表Resource操作测试")
@DisplayName("database table Resource test")
class AuthResourceDaoTest extends TomApplicationTest {
@Autowired
private AuthResourceDao authResourceDao;
@DisplayName("插入数据Resource应正确")
@DisplayName("insert data in resource should success")
@Test
@Transactional
public void shouldSuccessWhenInsertResource() {
AuthResourceDO resource = AuthResourceDO.builder()
.name("角色管理").code("ROLE_MANAGE")
.name("role_manager").code("ROLE_MANAGE")
.uri("/index/role").status(1)
.method("post").build();
resource = authResourceDao.save(resource);
......@@ -36,19 +36,19 @@ class AuthResourceDaoTest extends TomApplicationTest {
}
/**
* todo 这里加事务有点问题 resourceUpdate在数据库改变后,resource也会被改变 why?
* todo something error happen, resource would change when resourceUpdate update in @Transactional, why?
*/
@DisplayName("更新数据Resource应正确")
@DisplayName("update resource data should success")
@Test
public void shouldSuccessWhenUpdateResource() {
AuthResourceDO resource = AuthResourceDO.builder()
.name("角色管理").code("ROLE_MANAGE")
.name("role_manager").code("ROLE_MANAGE")
.uri("/index/role").status(1)
.method("post").build();
resource = authResourceDao.saveAndFlush(resource);
AuthResourceDO resourceUpdate = AuthResourceDO.builder()
.id(resource.getId())
.name("角色管理2").code("ROLE_MANAGE2")
.name("role_manager2").code("ROLE_MANAGE2")
.uri("/index/role2").status(2)
.method("get").build();
resourceUpdate = authResourceDao.saveAndFlush(resourceUpdate);
......@@ -56,12 +56,12 @@ class AuthResourceDaoTest extends TomApplicationTest {
Assertions.assertThat(resourceUpdate).isNotNull().isNotEqualTo(resource);
}
@DisplayName("删除数据Resource应正确")
@DisplayName("delete resource data should success")
@Test
@Transactional
public void shouldSuccessWhenDeleteResource() {
AuthResourceDO resource = AuthResourceDO.builder()
.name("角色管理").code("ROLE_MANAGE")
.name("role_manager").code("ROLE_MANAGE")
.uri("/index/role").status(1)
.method("post").build();
resource = authResourceDao.save(resource);
......@@ -69,7 +69,7 @@ class AuthResourceDaoTest extends TomApplicationTest {
Assertions.assertThat(authResourceDao.findById(resource.getId()).isPresent()).isFalse();
}
@DisplayName("查询数据Resource===Method===Role应正确")
@DisplayName("select data:Resource===Method===Role should success")
@Test
@Transactional
public void shouldReturnSuccessWhenGetEnableResourcePathRoleData() {
......@@ -77,12 +77,12 @@ class AuthResourceDaoTest extends TomApplicationTest {
Assertions.assertThat(optional.isPresent()).isTrue();
}
@DisplayName("查询disable数据Resource===Method应正确")
@DisplayName("select data:Resource===Method should success")
@Test
@Transactional
public void shouldSuccessWhenGetDisableResourcePathData() {
AuthResourceDO resource = AuthResourceDO.builder()
.name("角色管理").code("ROLE_MANAGE")
.name("role_manager").code("ROLE_MANAGE")
.uri("/index/role/book").status(9)
.method("post").build();
authResourceDao.save(resource);
......
......@@ -13,29 +13,29 @@ import org.springframework.transaction.annotation.Transactional;
* @author tomsun28
* @date 23:59 2019-07-30
*/
@DisplayName("数据库表Role操作测试")
@DisplayName("database table Role test")
class AuthRoleDaoTest extends TomApplicationTest {
@Autowired
private AuthRoleDao authRoleDao;
@DisplayName("插入数据Role应成功")
@DisplayName("insert date in role should success")
@Test
@Transactional
public void shouldSuccessWhenInsertRole() {
AuthRoleDO authRole = AuthRoleDO.builder()
.name("管理员").code("role_admin")
.name("admin").code("role_admin")
.status(1).build();
authRole = authRoleDao.save(authRole);
Assertions.assertThat(authRole).isNotNull();
}
@DisplayName("删除数据Role应成功")
@DisplayName("delete data in role should success")
@Test
@Transactional
public void shouldSuccessWhenDeleteRole() {
AuthRoleDO authRole = AuthRoleDO.builder()
.name("管理员").code("role_admin")
.name("admin").code("role_admin")
.status(1).build();
authRole = authRoleDao.save(authRole);
authRoleDao.delete(authRole);
......
......@@ -15,7 +15,7 @@ import org.springframework.transaction.annotation.Transactional;
* @author tomsun28
* @date 00:10 2019-07-31
*/
@DisplayName("数据库表RoleResourceBind操作测试")
@DisplayName("database table RoleResourceBind test")
class AuthRoleResourceBindDaoTest extends TomApplicationTest {
@Autowired
......@@ -27,7 +27,7 @@ class AuthRoleResourceBindDaoTest extends TomApplicationTest {
@Autowired
private AuthRoleDao roleDao;
@DisplayName("插入数据Bind应成功")
@DisplayName("insert data in bind should success")
@Test
@Transactional
public void shouldSuccessWhenInsertBind() {
......@@ -37,7 +37,7 @@ class AuthRoleResourceBindDaoTest extends TomApplicationTest {
Assertions.assertThat(roleResourceBind).isNotNull();
}
@DisplayName("删除数据Bind应成功")
@DisplayName("delete data in bind should success")
@Test
@Transactional
public void shouldSuccessWhenDeleteBind() {
......@@ -48,24 +48,24 @@ class AuthRoleResourceBindDaoTest extends TomApplicationTest {
Assertions.assertThat(roleResourceBindDao.findById(roleResourceBind.getId()).isPresent()).isFalse();
}
@DisplayName("通过Bind关联应能查询角色拥有的资源")
@DisplayName("select resource which the role has with using RoleResourceBind should success")
@Test
@Transactional
public void shouldFindResourceWhenUseRoleBind() {
AuthResourceDO resource1 = AuthResourceDO.builder()
.name("角色管理").code("ROLE_MANAGE")
.name("role_manager").code("ROLE_MANAGE")
.uri("/index/role").status(1)
.method("post")
.build();
resourceDao.save(resource1);
AuthResourceDO resource2 = AuthResourceDO.builder()
.name("资源管理").code("RESOURCE_MANAGE")
.name("resource_manager").code("RESOURCE_MANAGE")
.uri("/index/resource").status(1)
.method("get")
.build();
resourceDao.save(resource2);
AuthRoleDO authRole = AuthRoleDO.builder()
.name("管理员").code("role_admin")
.name("admin").code("role_admin")
.status(1).build();
roleDao.save(authRole);
AuthRoleResourceBindDO roleResourceBind = AuthRoleResourceBindDO.builder()
......
......@@ -13,13 +13,13 @@ import org.springframework.transaction.annotation.Transactional;
* @author tomsun28
* @date 00:46 2019-07-31
*/
@DisplayName("数据库表User操作测试")
@DisplayName("database table User test")
class AuthUserDaoTest extends TomApplicationTest {
@Autowired
private AuthUserDao authUserDao;
@DisplayName("插入数据User应成功")
@DisplayName("insert data in User should success")
@Test
@Transactional
public void shouldSuccessWhenInsertUser() {
......@@ -30,7 +30,7 @@ class AuthUserDaoTest extends TomApplicationTest {
Assertions.assertThat(authUser).isNotNull();
}
@DisplayName("删除数据User应成功")
@DisplayName("delete data in User should success")
@Test
@Transactional
public void shouldSuccessWhenDeleteUser() {
......
......@@ -15,7 +15,7 @@ import org.springframework.transaction.annotation.Transactional;
* @author tomsun28
* @date 00:52 2019-07-31
*/
@DisplayName("数据库表UserRoleBind操作测试")
@DisplayName("database table UserRoleBind test")
class AuthUserRoleBindDaoTest extends TomApplicationTest {
@Autowired
......@@ -27,7 +27,7 @@ class AuthUserRoleBindDaoTest extends TomApplicationTest {
@Autowired
private AuthRoleDao roleDao;
@DisplayName("插入数据Bind应成功")
@DisplayName("insert data in UserRoleBind should success")
@Test
@Transactional
public void shouldSuccessWhenInsertBind() {
......@@ -37,7 +37,7 @@ class AuthUserRoleBindDaoTest extends TomApplicationTest {
Assertions.assertThat(userRoleBind).isNotNull();
}
@DisplayName("删除数据Bind应成功")
@DisplayName("delete data in UserRoleBind shoudl success")
@Test
@Transactional
public void shouldSuccessWhenDeleteBind() {
......@@ -48,16 +48,16 @@ class AuthUserRoleBindDaoTest extends TomApplicationTest {
Assertions.assertThat(userRoleBindDao.findById(userRoleBind.getId()).isPresent()).isFalse();
}
@DisplayName("通过Bind关联能查询用户拥有的角色")
@DisplayName("select roles which the user has with using UserRoleBind should success")
@Test
@Transactional
public void shouldFindRoleWhenUseUserBind() {
AuthRoleDO authRole1 = AuthRoleDO.builder()
.name("管理员").code("role_admin")
.name("admin").code("role_admin")
.status(1).build();
roleDao.save(authRole1);
AuthRoleDO authRole2 = AuthRoleDO.builder()
.name("操作员").code("role_access")
.name("controller").code("role_access")
.status(1).build();
roleDao.save(authRole2);
AuthUserDO authUser = AuthUserDO.builder()
......
......@@ -6,7 +6,7 @@ import io.quarkus.runtime.Startup;
import javax.enterprise.context.ApplicationScoped;
/**
* sureness 配置,使用默认的DefaultSurenessConfig
* sureness config,Use DefaultSurenessConfig
* @author tomsun28
* @date 23:38 2019-05-12
*/
......@@ -15,7 +15,7 @@ import javax.enterprise.context.ApplicationScoped;
public class SurenessConfiguration {
/**
* 初始化sureness默认配置
* init sureness default config
*/
public SurenessConfiguration() {
new DefaultSurenessConfig(DefaultSurenessConfig.SUPPORT_JAX_RS);
......
......@@ -16,7 +16,8 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
/**
* 程序的http request请求入口过滤类示例 所有request请求都需经过此类
* An example of the program's http request request entry filtering class.
* All request requests must go through this class
* @author tomsun28
* @date 17:22 2019-05-12
*/
......@@ -24,14 +25,15 @@ import javax.ws.rs.ext.Provider;
@PreMatching
public class SurenessFilterExample implements ContainerRequestFilter, ContainerResponseFilter {
/** 日志操作 **/
/** logger **/
private static final Logger logger = LoggerFactory.getLogger(SurenessFilterExample.class);
@Override
public void filter(ContainerRequestContext requestContext) {
try {
SubjectSum subject = SurenessSecurityManager.getInstance().checkIn(requestContext);
// 可以考虑使用SurenessContextHolder放入threadLocal中绑定
// You can consider using SurenessContextHolder to bind subject in threadLocal
// if bind, please remove it when end
if (subject != null) {
SurenessContextHolder.bindSubject(subject);
}
......
......@@ -24,7 +24,7 @@ import java.util.LinkedList;
import java.util.List;
/**
* sureness 配置
* sureness config
* @author tomsun28
* @date 23:38 2019-09-29
*/
......
......@@ -18,6 +18,7 @@ import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
/**
* sureness filter class example, filter all http request
* @author tomsun28
* @date 2020-09-29 22:02
*/
......@@ -34,7 +35,8 @@ public class SurenessFilterExample implements WebFilter {
String errorMsg = null;
try {
SubjectSum subject = SurenessSecurityManager.getInstance().checkIn(request);
// 可以考虑使用SurenessContextHolder放入threadLocal中绑定,如果绑定 请在请求线程结束时remove
// You can consider using SurenessContextHolder to bind subject in threadLocal
// if bind, please remove it when end
if (subject != null) {
SurenessContextHolder.bindSubject(subject);
}
......
......@@ -2,7 +2,6 @@ package com.usthe.sureness.spring.webflux.controller;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
......@@ -15,7 +14,7 @@ import java.util.Map;
import java.util.Objects;
/**
* 模拟资源controller,供测试调用
* simulate resource controller, for testing
* @author tomsun28
* @date 17:35 2019-05-12
*/
......@@ -190,9 +189,9 @@ public class SimulateController {
}
/**
* 获取MOCK固定的返回数据MAP
* @param exchange http 请求
* @return 返回数据
* get map data from exchange request
* @param exchange http request
* @return map data
*/
private Map<String, String> getResponseMap(ServerWebExchange exchange) {
ServerHttpRequest httpRequest = exchange.getRequest();
......
......@@ -13,7 +13,7 @@ import java.nio.charset.StandardCharsets;
import java.util.Base64;
/**
* 支持通过basic auth 创建PasswordSubject 的创建者
* the creator to create PasswordSubject(basic auth)
* only support reactive server-side HTTP request
* org.springframework.http.server.reactive.ServerHttpRequest
* @author tomsun28
......@@ -29,7 +29,6 @@ public class BasicSubjectReactiveCreator implements SubjectCreate {
@Override
public boolean canSupportSubject(Object context) {
// basic auth判断
// ("Authorization", "Basic YWRtaW46YWRtaW4=") --- basic auth
if (context instanceof ServerHttpRequest) {
String authorization = ((ServerHttpRequest)context).getHeaders().getFirst(AUTHORIZATION);
......
......@@ -8,8 +8,8 @@ import org.springframework.http.server.reactive.ServerHttpRequest;
import java.net.InetSocketAddress;
/**
* 无认证信息的subject creator
* 所有请求都能创建出一个NoneSubject
* the creator to create NoneSubject - no auth info
* all request can be created a NoneSubject by NoneSubjectReactiveCreator
* only support ServerHttpRequest
* @author tomsun28
* @date 22:55 2020-09-29
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册