最近在写登录策略配置LoginConfig模块,现在通过分析登录策略配置模块来说明系统的层次结构。系统后台主要包括四层:
1. 数据库层:包括表、存储过程、实体类
2. 数据访问层:数据访问对象(也就是Dao层)
3. 后端逻辑层:查询与命令类
4. Rest接口层:资源类
数据库层
登录限制策略模块包括一张login_configs表,6个存储过程(Insertloginconfigs,Updateloginconfigs,Deleteloginconfigs,GetAllFromloginconfigs,GetloginconfigsById和GetloginconfigsByName),以及一个LoginConfis的实体类
LoginConfigs表格只有6个字段,在create_tables.sql中创建表格
//create_tables.sql
CREATE TABLE login_configs (
loginconfig_id uuid NOT NULL,
role_name character varying(255) NOT NULL,
time_limit character varying(4000),
ip_limit character varying(4000),
mac_limit character varying(4000),
other character varying(4000)
);
存储过程:比如增加Insertloginconfigs
CREATE OR REPLACE FUNCTION Insertloginconfigs(
v_loginconfig_id uuid,
v_role_name VARCHAR(255),
v_time_limit VARCHAR(4000),
v_ip_limit VARCHAR(4000),
v_mac_limit VARCHAR(4000),
v_other VARCHAR(4000)
)RETURNS VOID AS $PROCEDURE$
BEGIN
INSERT INTO login_configs (loginconfig_id,role_name,time_limit,ip_limit,mac_limit,other)
VALUES (v_loginconfig_id,v_role_name,pgp_sym_encrypt(v_time_limit,'engine'),pgp_sym_encrypt(v_ip_limit,'engine'),pgp_sym_encrypt(v_mac_limit,'engine'),pgp_sym_encrypt(v_other,'engine'));
END;$PROCEDURE$
LANGUAGE plpgsql;
实体类LoginConfig
public class LoginConfigs implements IVdcQueryable, BusinessEntity<Guid>{
private static final long serialVersionUID = 3090608330047174149L;
//进程Id
private Guid id;
@Override
public Guid getId() {
return id;
}
@Override
public void setId(Guid id) {
this.id = id;
}
//角色名
private String roleName;
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
//限制时间
private String timeLimit;
public String getTimeLimit() {
return timeLimit;
}
public void setTimeLimit(String timeLimit) {
this.timeLimit = timeLimit;
}
//限制IP
private String macLimit;
public String getMacLimit() {
return macLimit;
}
public void setMacLimit(String macLimit) {
this.macLimit = macLimit;
}
//限制IP
private String ipLimit;
public String getIpLimit() {
return ipLimit;
}
public void setIpLimit(String ipLimit) {
this.ipLimit = ipLimit;
}
//预留字段
private String other;
public String getOther() {
return other;
}
public void setOther(String other) {
this.other = other;
}
public LoginConfigs(){
id = Guid.Empty;
roleName = "";
timeLimit = "";
ipLimit = "";
other = "";
}
@Override
public Object getQueryableId() {
return getId();
}
@Override
public int hashCode() {
return Objects.hash(id,roleName,timeLimit,ipLimit,other);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof LoginConfigs)) {
return false;
}
LoginConfigs configs = (LoginConfigs) obj;
return Objects.equals(id, configs.id)
&& Objects.equals(roleName, configs.roleName)
&& Objects.equals(timeLimit, configs.timeLimit)
&& Objects.equals(ipLimit, configs.ipLimit)
&& Objects.equals(other, configs.other);
}
}
添加完LoginConfigs.java后配置在Common.gwt.xml中,否则 将不能被部分包所使用
数据访问层
DbFacade:数据库的外观器
LoginConfigsDao:数据访问对象接口层
//LoginConfigsDao.java
public interface LoginConfigsDao extends Dao,SearchDao<LoginConfigs>{
void save(LoginConfigs loginConfigs);
void update(LoginConfigs loginConfigs);
void detele(Guid id);
LoginConfigs getById(Guid id);
LoginConfigs getByName(String roleName);
List<LoginConfigs> getAll();
}
LoginConfigsDaoImpl:数据访问对象实现类
public class LoginConfigsDaoImpl extends BaseDao implements LoginConfigsDao{
private RowMapper<LoginConfigs> loginConfigsRowMapper = (rs ,rowNum) -> {
LoginConfigs entity = new LoginConfigs();
entity.setId(getGuidDefaultEmpty(rs,"loginconfig_id"));
entity.setRoleName(rs.getString("role_name"));
entity.setTimeLimit(rs.getString("time_limit"));
entity.setIpLimit(rs.getString("ip_limit"));
entity.setMacLimit(rs.getString("mac_limit"));
entity.setOther(rs.getString("other"));
return entity;
};
@Override
public List<LoginConfigs> getAllWithQuery(String query) {
return null;
}
@Override
public void save(LoginConfigs loginConfigs) {
Guid id = loginConfigs.getId();
if(Guid.isNullOrEmpty(id)){
id = Guid.newGuid();
loginConfigs.setId(id);
}
getCallsHandler().executeModification("Insertloginconfigs",createFullParametersMapper(loginConfigs ));
}
@Override
public void update(LoginConfigs loginConfigs) {
getCallsHandler().executeModification("Updateloginconfigs", createFullParametersMapper(loginConfigs));
}
@Override
public void detele(Guid id) {
getCallsHandler().executeModification("Deleteloginconfigs", createIdParameterMapper(id));
}
@Override
public LoginConfigs getById(Guid id) {
return getCallsHandler().executeRead("GetloginconfigsById",loginConfigsRowMapper,createIdParameterMapper(id));
}
@Override
public LoginConfigs getByName(String roleName) {
MapSqlParameterSource parameterSource = getCustomMapSqlParameterSource().addValue("role_name", roleName);
return getCallsHandler().executeRead("GetloginconfigsByName", loginConfigsRowMapper, parameterSource);
}
@Override
public List<LoginConfigs> getAll() {
return getCallsHandler().executeReadList("GetAllFromloginconfigs",loginConfigsRowMapper,getCustomMapSqlParameterSource());
}
private MapSqlParameterSource createIdParameterMapper(Guid id){
return getCustomMapSqlParameterSource().addValue("loginconfig_id", id);
}
private MapSqlParameterSource createFullParametersMapper(LoginConfigs entity) {
return createIdParameterMapper(entity.getId())
.addValue("ip_limit",entity.getIpLimit())
.addValue("mac_limit",entity.getMacLimit())
.addValue("time_limit",entity.getTimeLimit())
.addValue("role_name",entity.getRoleName())
.addValue("other",entity.getOther());
}
}
后端逻辑层
后端逻辑层是对操作命令化,把每种操作请求都封装成命令的形式
[参数]
1. LoginConfigsOperationParameters 模块操作的基本参数类
2. AddLoginConfigsCommand 添加操作的参数类
3. RemoveLoginConfigsParameters 更新操作的参数类
4. UpdateLoginConfigsParameters 删除操作的参数类
【查询与命令】
1. GetAllLoginConfigsQuery 获取所有登录策略的查询类
2. GetLoginConfigByIdQuery 根据id获取指定的登录策略的查询类
3. GetLoginConfigByNameQuery 根据角色名获取指定登录策略的查询类
4. AddLoginConfigsCommand 添加LoginConfigs的命令类
5. RemoveLoginConfigsCommand 删除LoginConfigs的命令类
6. UpdateLoginConfigsCommand 更新LoginConfigs的命令类
【类型】
1. VdcActionType 动作类型集合
2. VdcQueryType 查询类型集合
3. VdcObjectType 对象类型集合
4. ActionGroup 动作组集合
//LoginConfigsOperationParameters.java 是所有操作的参数类的父类
public class LoginConfigsOperationParameters extends VdcActionParametersBase{
private static final long serialVersionUID = 3991635679508928037L;
@Valid
private LoginConfigs loginConfigs;
public LoginConfigsOperationParameters(){
}
public LoginConfigsOperationParameters(Guid id){
this.setId(id);
loginConfigs.setId(id);
}
public LoginConfigsOperationParameters(LoginConfigs _loginConfigs){
loginConfigs = _loginConfigs;
}
public Guid getId(){
return loginConfigs == null ? null : loginConfigs.getId();
}
public void setId(Guid id){
if(loginConfigs == null){
loginConfigs = new LoginConfigs();
}
loginConfigs.setId(id);
}
public String getName(){
return loginConfigs == null ? null : loginConfigs.getRoleName();
}
public void setName(String name){
if(loginConfigs == null){
loginConfigs = new LoginConfigs();
}else {
loginConfigs.setRoleName(name);
}
}
public LoginConfigs getLoginConfigs(){
return loginConfigs;
}
public void setLoginConfigs(LoginConfigs loginConfigs){
this.loginConfigs = loginConfigs;
}
}
添加操作的参数类
public class AddLoginConfigsParameters extends LoginConfigsOperationParameters{
private static final long serialVersionUID = -7832310521101821905L;
public AddLoginConfigsParameters(LoginConfigs loginConfigs){
super(loginConfigs);
}
}
获取所有登录策略的查询类
public class GetAllLoginConfigsQuery <P extends VdcQueryParametersBase> extends QueriesCommandBase<P>{
public GetAllLoginConfigsQuery(P parameters) {
super(parameters);
}
@Override
protected void executeQueryCommand() {
getQueryReturnValue().setReturnValue(getDbFacade().getLoginConfigsDao().getAll());
}
}
添加登录限制策略的命令类
public class AddLoginConfigsCommand <T extends AddLoginConfigsParameters> extends AbstractCommand<T> {
public AddLoginConfigsCommand(T parameters, CommandContext cmdContext) {
super(parameters, cmdContext);
}
public AddLoginConfigsCommand(Guid commandId) {
super(commandId);
}
@Override
protected void executeCommand() {
DbFacade dbFacade = DbFacade.getInstance();
getParameters().setId(Guid.newGuid());
DbUser user = getCurrentUser();
LoginConfigs configs = getParameters().getLoginConfigs();
if (configs == null) {
setSucceeded(false);
return;
}
String roleName = configs.getRoleName() == null ? "" : configs.getRoleName();
if (user != null) {
if (user.getLoginName().equals("systemAdmin")) {
setSucceeded(false);
} else if (user.getLoginName().equals("securityAdmin")) {
//保密员配置普通用户角色的登录策略
if (roleName.contains("SystemAdmin") || roleName.contains("AuditAdmin")|| roleName.contains("UserRole")) {
dbFacade.getLoginConfigsDao().save(configs);
setSucceeded(true);
}
} else if (user.getLoginName().equals("auditAdmin")) {
if (roleName.contains("SecurityAdmin")) {
dbFacade.getLoginConfigsDao().save(configs);
setSucceeded(true);
}
}
} else {
setSucceeded(false);
}
}
//检测权限
@Override
public List<PermissionSubject> getPermissionCheckSubjects() {
return Collections.singletonList(new PermissionSubject(Guid.SYSTEM,
VdcObjectType.System, ActionGroup.LOGIN_CONFIG));
}
//记录日志
@Override
public AuditLogType getAuditLogTypeValue() {
return getSucceeded() ? AuditLogType.ADD_LOGIN_CONFIGS
: AuditLogType.ADD_LOGIN_CONFIGS_ERROR;
}
}
VdcQueryType.java 对新增的查询类添加对应的枚举类
GetAllLoginConfigs(RoleType.USER),
GetLoginConfigById(RoleType.USER),
GetLoginConfigByName(RoleType.USER),
VdcActionType 对新增的命令类添加对应的枚举类
AddLoginConfigs(8004,ActionGroup.LOGIN_CONFIG,false,QuotaDependency.NONE),
UpdateLoginConfigs(8005,ActionGroup.LOGIN_CONFIG,false,QuotaDependency.NONE),
RemoveLoginConfigs(8006,ActionGroup.LOGIN_CONFIG,false,QuotaDependency.NONE),
ActionGroup 与角色权限有关
LOGIN_CONFIG(1701,RoleType.USER, false),
Rest接口层
BackendLoginConfigsResource 主资源实现类
BackendLoginConfigResource 子资源实现类
BackendApiResource 后台应用类,用于分发请求
LoginConfigsResource 主资源接口类
LoginConfigResource 子资源接口类
SystemResource
LoginConfigsResource 主资源
@Produces(ApiMediaType.APPLICATION_JSON)
public interface LoginConfigsResource {
@POST
@Consumes(ApiMediaType.APPLICATION_JSON)
default Response add(LoginConfigs loginConfigs) {
throw new UnsupportedOperationException();
}
@GET
default List<LoginConfigs> list() {
throw new UnsupportedOperationException();
}
@POST
@Consumes(ApiMediaType.APPLICATION_JSON)
@Path("getByname")
default LoginConfigs getByName (LoginConfigs loginConfigs) {
throw new UnsupportedOperationException();
}
@Path("{id}")
LoginConfigResource getLoginConfigResource(@PathParam("id") String id);
}
LoginConfigResource 子资源
@Produces({ApiMediaType.APPLICATION_XML, ApiMediaType.APPLICATION_JSON})
public interface LoginConfigResource {
@DELETE
default Response remove() {
throw new UnsupportedOperationException();
}
@GET
default LoginConfigs get() {
throw new UnsupportedOperationException();
}
@PUT
@Consumes(ApiMediaType.APPLICATION_JSON)
default LoginConfigs update(LoginConfigs loginConfigs) {
throw new UnsupportedOperationException();
}
}
BackendLoginConfigsResource 主资源实现类
public class BackendLoginConfigsResource extends BackendResource implements LoginConfigsResource {
@Override
public Response add(LoginConfigs loginConfigs) {
return performAction(VdcActionType.AddLoginConfigs,new AddLoginConfigsParameters(loginConfigs));
}
@Override
public List<LoginConfigs> list() {
VdcQueryReturnValue returnValue = runQuery(VdcQueryType.GetAllLoginConfigs, new VdcQueryParametersBase());
return returnValue.getReturnValue();
}
@Override
public LoginConfigs getByName(LoginConfigs loginConfigs) {
String roleName = loginConfigs.getRoleName();
VdcQueryReturnValue returnValue = runQuery(VdcQueryType.GetLoginConfigByName, sessionize(new NameQueryParameters(roleName)));
return returnValue.getReturnValue();
}
@Override
public LoginConfigResource getLoginConfigResource(String id) {
return inject(new BackendLoginConfigResource(id));
}
}
BackendLoginConfigsResource 子资源实现类
public class BackendLoginConfigResource extends BackendResource implements LoginConfigResource{
protected Guid id;
public BackendLoginConfigResource(String id){
this.id = asGuid(id);
}
@Override
public Response remove(){
return performAction(VdcActionType.RemoveLoginConfigs,new RemoveLoginConfigsParameters(id));
}
@Override
public LoginConfigs get(){
VdcQueryReturnValue returnValue = runQuery(VdcQueryType.GetLoginConfigById, sessionize(new IdQueryParameters(id)));
return returnValue.getReturnValue();
}
@Override
public LoginConfigs update(LoginConfigs loginConfigs) {
loginConfigs.setId(this.id);
Response response = performAction(VdcActionType.UpdateLoginConfigs,new UpdateLoginConfigsParameters(loginConfigs));
if (response.getStatus() == 200) {
return runQuery(VdcQueryType.GetLoginConfigById, sessionize(new IdQueryParameters(id))).getReturnValue();
}
return null;
}
}
systemResource
@Path("/")
@Produces(MediaType.APPLICATION_JSON)
public interface SystemResource {
@Path("loginConfigs")
LoginConfigsResource getLoginConfigsResource();
....
}
至此登录限制策略的后台接口已完成,可通过loginconfigs接口对登录策略进行增删改查。这样实现起来简单明了,不过由于是根据角色定义登录限制策略,同一种角色只有一种登录限制策略,对不同用户暂时不能做到多样性控制,后期再修正。还有就是有多条限制策略时都存在同一张表的同一个字段中,前台需做一些处理。