GVKun编程网logo

AAA - ActFramework的安全框架 I - 概念及简介(安全框架有哪些)

24

本文将介绍AAA-ActFramework的安全框架I-概念及简介的详细情况,特别是关于安全框架有哪些的相关信息。我们将通过案例分析、数据研究等多种方式,帮助您更全面地了解这个主题,同时也将涉及一些关

本文将介绍AAA - ActFramework的安全框架 I - 概念及简介的详细情况,特别是关于安全框架有哪些的相关信息。我们将通过案例分析、数据研究等多种方式,帮助您更全面地了解这个主题,同时也将涉及一些关于.Net Core AA.FrameWork 应用框架介绍、AAA - ActFramework的安全框架II - 应用、ActFramework 1.0 正式发布, Java MVC 框架、ActFramework 1.0.2 发布, Java MVC 框架的知识。

本文目录一览:

AAA - ActFramework的安全框架 I - 概念及简介(安全框架有哪些)

AAA - ActFramework的安全框架 I - 概念及简介(安全框架有哪些)

1. AAA 以及相关概念

1.1 Authentication (AE) - 认证

确认与系统交互的用户或者进程身份的过程

1.2 Authorisation (AO) - 授权

当 Principal (身份主体) 访问系统资源时依据主体授权允许或者拒绝其访问的过程

1.3 Accounting (AC) - 记账

记录 Principal 对系统资源的访问操作

1.4 Principal - 身份主体

系统中对交互对象的唯一识别. 交互对象可以是一个用户, 也可以是一个外部进程.

1.5 Permission - 资源权限

对确定资源的访问资格

1.5.1 Dynamic Permission - 动态资源权限

osgl-aaa提出的概念, 如果某种资源权限被设置为动态, 表示在授权过程中非但需要对用户是否拥有该资源权限进行检查, 还必须检查用户和资源之间是否关联. 比如, 用户 A 不能修改用户 B 拥有的数据, 即使 A 拥有相应的资源权限

1.6 Role - 角色

Role 是一组定义好的 Permission 的集合. Role 可以用来方便地就相关联的权限组合对 Principal 进行授权或者取消授权

1.7 Privilege - 特权

和 Permission 不同, Privilege 并不针对特定的资源. Privilege 依赖于级别 (一个Integer) 来判断是否有权限访问某些资源. 举个具体的例子, 假设某个资源要求访问级别是5, 当前 Principal 的访问级别是 6, 则应该授权访问. 比较一下 Permission 的授权过程, 假设访问某个资源要去的 Permission 是 "create-order", 而当前 Principal 没有这个 Permission, 则拒绝访问.

另一个不同之处是, 一个 Principal 可以有多个 Permission (直接或者间接通过 Role 获得), 但一个 Principal 最多有一个 Privilege

1.8 概念之间的关系

Principal 可以有

  • 零到多个 Roles
  • 零到多个 Permissions
  • 零个或者一个 Privilege

Role 可以有

  • 零到多个 Permissions

2. osgl-aaa 和 act-aaa-plugin

osgl-aaa 是一个通用的Java AAA框架和工具集. 实现了上面所述的概念和逻辑

act-aaa-plugin插件将 osgl-aaa 框架和ActFramework集成起来, 负责配置管理, 服务发现, 并实现了在 osgl-aaa 中定义的一些接口, 以及一些工具类.

在以后的 AAA 系列博客中我们将一起从头到尾实现一个完整的带用户注册, 登录, 授权功能演示的小型系统.

参考

  • ActFramework 官网
  • ActFramework视频
  • AAA - ActFramework的安全框架II - 应用
  • simple-bbs - AAA 演示项目1
  • Yet Another Todo List - AAA 演示项目2

.Net Core AA.FrameWork 应用框架介绍

.Net Core AA.FrameWork 应用框架介绍

 开发多年,一直在从社区获取开源的便利,也深感社区力量的重要性,今天开源一个应用基础框架 AA.FrameWork, 也算是回馈社区,做出一点点贡献,希望能够帮助类似当年入行的我。 

 AA.FrameWork 是基于.NET core 流行的开源类库创建的基础应用框架。

 框架代码图如:

源代码 github 地址:https://github.com/ChengLab/AAFrameWork

nuget 管理中,搜索前缀名称 AA 即可如图

Nuget Packages

Package nuget description
AA.Dapper nuget 基于 dapper,Dapper-FluentMap 开发 , 支持工作单元、仓储模式和原生 dapper 的操作
AA.Log4Net nuget 基于 Log4net 开发,提供常用的日志操作类
AA.FrameWork nuget 基础框架
AA.Redis nuget 基于 StackExchange.Redis 开发,提供各种 redis 操作和基于 redis 的分布式锁
AA.AutoMapper nuget 基于 AutoMapper 开发,对象映射
AA.ServiceBus nuget 基于 MassTransit 开发的服务总线 ;很方便的应用在 event bus 和 publish/subscribe 场景
AA.AspNetCore nuget aspnetcore 常用类集合

AA.Dapper 用法

实体映射配置

使用 DommelEntityMap<TEntity> 类映射属性名称。创建一个派生类,在构造函数中设置 Map 方法,可指定某个属性映射到数据库列名

public class UserInfoMap : DommelEntityMap<UserInfo>
    {
        public UserInfoMap()
        {
            ToTable("Sys_UserInfo");//映射具体的表名
            Map(p => p.SysNo).IsKey();//指定主键 ,IsIdentity是否自增
            Map(p=>p.GmtCreate).ToColumn("GmtCreateDate"); //属性名和数据库列名 可以不同
Map(p=>p.LastLoginDate).Ignore();//一些计算属性,可以忽略不需要跟数据库列进行映射 } }

使用 MapConfiguration.Init 方法,把映射类初始化,后续就可以使用了

public static void InitMapCfgs()
        {
            var fluentMapconfig = new List<Action<FluentMapConfiguration>>();
            fluentMapconfig.Add(cfg =>
            {
                cfg.AddMap(new UserInfoMap());
            });
            MapConfiguration.Init(fluentMapconfig);
        }

开始使用 AA.Dapper

使用 DapperContext 设置数据库连接和数据库类型是 sqlserver 还是 mysql
public class AADapperContext : DapperContext
    {
        public AADapperContext() : base(new NameValueCollection()
        {
            ["aa.dataSource.AaCenter.connectionString"] = "Data Source =.; Initial Catalog = AaCenter;User ID = sa; Password = 123;",
            ["aa.dataSource.AaCenter.provider"] = "SqlServer"
        })
        { }
    }
仓储包含了大部分的操作,同时支持 Async 操作
IDapperRepository<UserInfo> userInfoRepository = new DapperRepository<UserInfo>();
插入实体
var user = new UserInfo()
            {
                UserName = "chengTian",
                RealName = "成天",
                GmtCreate = DateTime.Now,
                GmtModified = DateTime.Now
            };
  var result = userInfoRepository.Insert(user);
修改实体
var user = userInfoRepository.Get(1);
            user.GmtModified = DateTime.Now;
 var result = userInfoRepository.Update(user);

 

获取实体
var user = userInfoRepository.Get(1);//By 主键
   var users = userInfoRepository.GetAll();//所有
   var users = userInfoRepository.Select(p => p.UserName == "chengTian");//谓词

 

删除实体
var user = userInfoRepository.Get(1);
   var result = userInfoRepository.Delete(user);
支持 Dapper 原生操作

操作基本的封装都是单表的操作,可以满足一部分业务开发,有些业务场景编写 sql 还是比较合适的比如报表和一些复杂的查询,推荐使用原生 dapper 的操作

public class UserInfoRepository : DapperRepository<UserInfo>, IUserInfoRepository
    {
        private readonly IDapperContext _dapperContext;
        public UserInfoRepository(IDapperContext context)
        {
            _dapperContext = context;
        }

        public IEnumerable<UserInfo> QueryAll()
        {
            var result = _dapperContext.DataBase.Query<UserInfo>("SELECT * from  [Sys_UserInfo]");//实例
            return result;
        }
    }

AA.Log4Net 用法

  1. log4net.config 配置,并将 log4net.config 的属性 -> 复制到输出目录 -> 设置为 -> 始终复制
  2. Log4NetLogger.Use ("配置文件名或者路径 + 配置文件名"); 例如:log4net.config 文件在根目录下,Log4NetLogger.Use ("log4net.config"); 如果在自定义文件中;例如 config/log4net.config 则 Log4NetLogger.Use ("config/log4net.config")
  3. ILog log= Logger.Get (typeof (类)); log.Debug ("example");

AA.ServiceBus 用法

生产者(事件和命令两种类型)

实例化 bus

//事件
 IBusControl busControl = ServiceBusManager.Instance.UseRabbitMq(rabbitMqUri, rabbitMqUserName, rabbitMqPassword)
                         .BuildEventProducer();
 //命令
 ISendEndpoint busControl = ServiceBusManager.Instance.UseRabbitMq(rabbitMqUri, rabbitMqUserName, rabbitMqPassword)
                         .BuildCommandProducer(queueName);

实例化 bus 之后可以使用发送和发布两个方法

//命令
  TaskUtil.Await(busControl.Send<SubmitOrder>(new
            {
                Id = 10
            }));
   //事件          
   TaskUtil.Await(busControl.Publish<OrderSubmitted>(new
            {
                Id = 1
            }));
消费者
[Fact]
        public void TestConsumer()
        {
            Log4NetLogger.Use("Log4Net/log4net.config");
            string rabbitMqUri = "rabbitmq://localhost:5672";
            string rabbitMqUserName = "";
            string rabbitMqPassword = "";
            string queueName = "order.queue";

            var busControl = ServiceBusManager.Instance.UseRabbitMq(rabbitMqUri, rabbitMqUserName, rabbitMqPassword)
             .RegisterConsumer<SubmitOrderCommandConsumer>(queueName)//注册命令消费者
             .RegisterConsumer<OrderSubmittedEventConsumer>(null)//注册事件消费者
             .Build();
            busControl.Start();

        }

定义消费者需要实现接口 IConsumer

public class OrderSubmittedEventConsumer : IConsumer<OrderSubmitted>
    {
        public async Task Consume(ConsumeContext<OrderSubmitted> context)
        {
            var @event = context.Message;

            var result = $"OrderSubmittedEvent {@event.Id.ToString()}";
            ILog log = Logger.Get(typeof(OrderSubmittedEventConsumer));
            log.Debug(result);
            //do somethings...
        }
    }


    public class SubmitOrderCommandConsumer : IConsumer<SubmitOrder>
    {
        public async Task Consume(ConsumeContext<SubmitOrder> context)
        {
            var command = context.Message;

            var result = $"CreateFooCommand {command.Id.ToString()}";
            ILog log = Logger.Get(typeof(SubmitOrderCommandConsumer));
            log.Debug(result);
            //do somethings...
        }
    }

AA.AutoMapper 用法

实现 IMapperConfiguration 接口,创建映射规则配置
public class WebMapperConfigurations : IMapperConfiguration
    {
        public int Order { get { return 0; } }

        public Action<IMapperConfigurationExpression>  GetConfiguration()
        {
            Action<IMapperConfigurationExpression> action = cfg =>
            {
                cfg.CreateMap<UserVm, UserInput>();
            };
            return action;
        }
    }
在程序 startup 调用配置
var mapperConfig = new WebMapperConfigurations();
     AutoMapperConfiguration.Init(new List<Action<IMapperConfigurationExpression>> { mapperConfig.GetConfiguration() });
     ObjectMapping.ObjectMapManager.ObjectMapper = new AutoMapperObjectMapper();
利用扩展方法 MapTo 执行映射
 [Fact]
        public void TestMap()
        {
            //init
            Init();
            UserVm userVm = new UserVm { Id = 1, Name = "成天" ,Remark="微信公众号:dotNet知音"};
            var userDto = userVm.MapTo<UserInput>();
            //var userDto2 = userVm.MapTo<UserVm,UserInput>();

        }

后面也会提供基于 AA 框架的应用实例,有问题可以联系我,一起交流和成长。

原文出处:https://www.cnblogs.com/chengtian/p/11684860.html

AAA - ActFramework的安全框架II - 应用

AAA - ActFramework的安全框架II - 应用

在上一篇博客中我们介绍了 AAA 安全框架的概念. 下面我们开始讲述实际项目中 (本篇博客将实现一个多用户的 Todo 列表系统) 如何使用 AAA 安全框架. 在本博客中我们将假设应用使用 MongoDB 来存储数据. 不过关于安全框架应用的部分代码和具体数据库无关.

1 引入项目依赖

在你的 pom.xml 文件中添加 act-aaa 插件依赖:

    <dependency>
      <groupId>org.actframework</groupId>
      <artifactId>act-aaa</artifactId>
      <version>${act-aaa.version}</version>
    </dependency>

其中 ${act-aaa.version} 是 act-aaa 插件的版本. 截止本文到落笔时的最新版本是 1.0.2.

**注意: ** 当你的项目加入依赖之后发生的最直接的变化是所有的控制器响应方法都需要身份认证了. 如果你没有进一步做任何工作, 所有的访问都会被返回 401 Unauthorised 响应.

2 处理不需要身份认证的控制器方法

act-aaa 插件默认所有的 HTTP 访问都需要身份认证. 但很明显任何 web 应用都有不需要身份认证的访问结构, 最简单的例子是登陆和注册.

如果某个响应方法不需要身份认证, 可以在该方法上添加 @org.osgl.aaa.NoAuthentication 注解:

@NoAuthentication
public void loginForm() {}

如果某个控制器所有的响应方法都不需要身份认证, 可以在控制器类上添加 @org.osgl.aaa.NoAuthentication 注解:

@NoAuthentication
public class PublicAccessController {
    ...
}

3 Model 类

3.1 创建一个 UserLinked 接口

UserLinked 接口将被用于检查具体某个被保护的资源是否属于当前正在访问的用户:

package demo.security;

public interface UserLinked {
    /**
     * Return the user ID 
     */
    public String userId();
}

3.2 创建 User 类

每个需要身份认证的应用都需要一个 Model 类来对正在和系统交互的用户建模. 下面是一个基本的 User 类代码. 具体应用可以增加自己需要的字段和逻辑

package demo.model;

@Entity("user")
public class User extends MorphiaAdaptiveRecord<User> implements UserLinked {

    public String email;
    private String password;

    @Override
    public String userId() {
        return this.email;
    }

    public void setPassword(String password) {
        this.password = Act.crypto().passwordHash(password);
    }

    public boolean verifyPassword(char[] password) {
        return Act.crypto().verifyPassword(password, this.password);
    }

    public static class Dao extends MorphiaDao<User> {

        public User findByEmail(String email) {
            return findOneBy("email", email);
        }

    }

}

注意 我们在 User 类中使用了 ActFramework 提供的工具来对密码明文进行哈希运算以及校验操作. 关于这方面更多的知识可以参见此篇博客.

3.3 创建 TODO 类

我们在本篇博客中实现一个多用户的 TODO 列表管理. 下面是一个简单的 TODO Model 类:

package demo.model;

@Entity("todo")
public class Todo extends MorphiaAdaptiveRecord<Todo> implements UserLinked {

    /**
     * Store the owner''s email
     */
    public String owner;

    @Override
    public String userId() {
        return this.owner;
    }
    
    public static class Dao extends MorphiaDao<Todo> {
        
        public Iterable<Todo> findByOwner(User owner) {
            return findBy("owner", owner.email);
        }
        
    }
    
}

4. 配置安全层

4.1 定义权限

AAA 的 API 支持使用两种权限, 第一传入某个实现了 org.osgl.aaa.Permission 的类实例; 第二传入某个字符串. 在此篇博客中我们将使用第二种简单形式. 下面定义在这个 TODO 应用中涉及到的权限:

package demo.security;

public final class TodoPermission {

    private TodoPermission() {}

    public static final String PERM_CREATE_TODO_ITEM = "create-todo-item";
    public static final String PERM_UPDATE_TODO_ITEM = "update-todo-item";
    public static final String PERM_VIEW_TODO_ITEM = "view-todo-item";
    public static final String PERM_DELETE_TODO_ITEM = "delete-todo-item";

}

上面的 TodoPermission 类主要是为了在应用中方便地使用权限常量. 下面我们将定义一个配置文件来告诉 act-aaa 应用中使用的权限及其特性. 在 src/main/resources/ 目录下添加一个名为 acl.yaml 的文件, 内容如下:

create-todo-item:
  type: permission
  dynamic: false

update-todo-item:
  type: permission
  dynamic: true

view-todo-item:
  type: permission
  dynamic: true

delete-todo-item:
  type: permission
  dynamic: true

注意 在上面的定义中除了 create-todo-item 权限, 其他所有权限的 dynamic 属性均为 true, 这是因为只有当需要校验 create-todo-item 的时候我们不需要校验数据 (i.e. Todo 实例, 因为还没有创建), 而其他权限都需要检查被访问的数据 (i.e Todo 实例) 是否属于当前用户.

4.2 配置应用安全框架

此步骤将使用一个类来设置 act-aaa 的各种配置:

package demo.security;

/**
 * Here we use the generic parameter to tell act-aaa about the user model class
 */
public class TodoSecurity extends ActAAAService.Base<demo.model.User> {


    /**
     * In this simple Todo app every signed up user get granted 
     * all of the following permissions
     */
    private static final Set<String> DEFAULT_PERMS = C.set(
            PERM_CREATE_TODO_ITEM, 
            PERM_DELETE_TODO_ITEM, 
            PERM_UPDATE_TODO_ITEM,
            PERM_VIEW_TODO_ITEM
    );

    /**
     * We tell act-aaa `email` is the key to extract the user from database
     */
    @Override
    protected String userKey() {
        return "email";
    }

    /**
     * Just return the default permission set 
     */
    @Override
    protected Set<String> permissionsOf(User user) {
        return DEFAULT_PERMS;
    }

    /**
     * inject the logic of password verification into act-aaa
     */
    @Override
    protected boolean verifyPassword(User user, char[] password) {
        return user.verifyPassword(password);
    }

    /**
     * This will help to check a protected resource against the current logged in user
     * if the permission been authorised is dynamic
     */
    public static class DynamicPermissionChecker extends DynamicPermissionCheckHelperBase<UserLinked> {
        @Override
        public boolean isAssociated(UserLinked userLinked, Principal principal) {
            return S.eq(userLinked.userId(), principal.getName());
        }
    }

}

5. 控制器

5.1 登陆注册控制器

package demo.controller;

public class LoginController {
        @Inject
    private User.Dao userDao;

    @GetAction("/login")
    public void loginForm() {
    }

    @PostAction("/login")
    public void login(String email, String password, H.Flash flash, ActionContext context) {
        User user = userDao.authenticate(email, password);
        if (null == user) {
            flash.error("cannot find user by email and password combination");
            redirect("/login");
        }
        context.login(email);
        redirect("/");
    }

    @GetAction("/sign_up")
    public void signUpForm() {
    }

    @PostAction("/sign_up")
    public void signUp(User user, ActionContext context, @Provided PostOffice postOffice) {
        if (userDao.exists(user.email)) {
            context.flash().error("User already exists");
            redirect("/sign_up");
        }
        user.activated = false;
        userDao.save(user);
        postOffice.sendWelcomeLetter(user);
        redirect("/sign_up_ok");
    }

    @GetAction("/sign_up_ok")
    public void signUpConfirm() {
    }

    @GetAction("/activate")
    public void activate(String tk, ActionContext context) {
        Token token = Act.crypto().parseToken(tk);
        notFoundIfNot(token.isValid());
        User user = userDao.findByEmail(token.id());
        notFoundIfNull(user);
        context.session("tk", tk);
        render(user);
    }

    @PostAction("/activate")
    public void completeActivation(String password, ActionContext context) {
        String tk = context.session("tk");
        notFoundIfNull(tk);
        Token token = Act.crypto().parseToken(tk);
        notFoundIfNot(token.isValid());
        User user = userDao.findByEmail(token.id());
        token.consume();
        user.setPassword(password);
        user.activated = true;
        userDao.save(user);
        context.login(user.email);
        redirect("/");
    }

}

该控制器主要实现了下列功能:

  1. 登陆
  2. 注册并发送激活邮件
  3. 响应激活链接请求
  4. 处理激化请求(初始化密码)

5.2 Todo控制器

@Controller("/todo")
public class TodoController extends AuthenticatedController {

    @Inject
    private TodoItem.Dao dao;

    @GetAction
    public Iterable<TodoItem> myItems() {
        AAA.requirePermission(me, PERM_VIEW_TODO_ITEM);
        return dao.findBy("owner", me.email);
    }

    @PostAction
    public TodoItem add(String subject) {
        AAA.requirePermission(me, PERM_CREATE_TODO_ITEM);
        TodoItem todoItem = new TodoItem(subject);
        todoItem.owner = me.email;
        return dao.save(todoItem);
    }

    @PutAction("{id}")
    public TodoItem update(@DbBind("id") TodoItem todo, String subject) {
        notFoundIfNull(todo);
        AAA.requirePermission(todo, PERM_UPDATE_TODO_ITEM);
        todo.subject = subject;
        return dao.save(todo);
    }

    @DeleteAction("{id}")
    public void delete(@DbBind("id") TodoItem todo) {
        notFoundIfNull(todo);
        AAA.requirePermission(todo, PERM_DELETE_TODO_ITEM);
        dao.delete(todo);
    }

}

该控制器提供操作 TODO 项的 RESTful 服务包括:

  1. 取当前用户所有的 TODO 项
  2. 创建新的 TODO 项目
  3. 修改已有的 TODO 项目
  4. 删除 TODO 项目

所有的请求均经过授权方予以执行

5.3 AuthenticatedController

public abstract class AuthenticatedController {
    @LoginUser
    protected User me;
}

提供该控制器是一个推荐用法, 所有需要用户登陆的控制器都可以继承该控制器, 并自动获取当前登陆用户的实例: this.me. 这是使用了 act-aaa 提供的 @LoginUser 注解, 并由 ActFramework 进行依赖注入的.

总结

本博客讲述了如何在应用中使用 act-aaa 插件, 包括:

  1. 引入依赖
  2. 创建应用的 User 类和其他 User 关联类
  3. 配置应用的 AAA 层
  4. 处理用户注册登陆以及激活帐号
  5. 在资源控制器方法上进行授权

本博客的项目代码保存在码云上: https://git.oschina.net/greenlaw110/yatl

参考

  • ActFramework 官网
  • ActFramework视频
  • AAA - ActFramework的安全框架I - 概念及简介
  • simple-bbs - AAA 演示项目1
  • Yet Another Todo List - AAA 演示项目2

ActFramework 1.0 正式发布, Java MVC 框架

ActFramework 1.0 正式发布, Java MVC 框架

ActFramework 是一个Java的非轻量级全栈式MVC框架. 和其他框架相比ActFramework的主要特点有:

  • 热加载. 开发过程(包括新增方法变量)不需要重启系统, 随时可以看到最新代码的效果

  • 强大的参数绑定. 控制器方法可以绑定任何Java类型,包括基本类型,字符串,enum,数组,集合类型,Map类型和用户自定义的POJO

  • 灵活的路由配置 - 支持注入和路由表配置

  • 符合JSR330标准的依赖注入

  • 内置CSRF,XSS防护

  • 内置CORS,支持SPA前后端分离

  • 功能完备的数据库访问层

  • 完整的RESTFul服务支持

  • 优秀的运行时性能

  • 支持不同运行环境的配置

  • 支持多种模板引擎

  • 非Servlet框架, 容易开发和部署

  • 多种插件,包括mongodb, Excel输出, OAuth认证,认证/授权/记账等

这次发布除了ActFramework核心框架还包括一些成熟可用的插件

  • actframework 1.0.1 - 核心框架

  • act-ebean 1.0.0 - SQL数据访问

  • act-morphia 1.0.0 - MongoDB访问

  • act-aaa 1.0.0 - 认证/授权/记账

  • act-excel 1.0.0 - Excel输出

  • act-storage 0.8.0 - 上传文件管理引擎

  • act-beetl - beetl模板支持

  • act-freemarker - freemarker模板支持

  • act-mustache - mustache模板支持

  • act-thymeleaf - thymeleaf模板支持

  • act-velocity - velocity模板支持

ActFramework将采用语义化版本管理发布. 

ActFramework 1.0.2 发布, Java MVC 框架

ActFramework 1.0.2 发布, Java MVC 框架

ActFramework 1.0.2 发布了,改进内容包括:

act-1.0.2

  • Fix # 88 Controller context break with intermediate non-controller class in the hierarchies

  • Fix #87 DependencyInjectionListener shall register with sub classes of the target class also

  • Fix #86 It shall allow null value for enum type parameter when do the request parameter binding

  • Fix #83 Hot reload will not process changes to messages resource bundles

act-morphia-1.0.1

  • Fix #4 MorphiaInjectionListener not effect on User defined Dao

act-ebean-1.0.1

  • Fix #1 EbeanDao.drop() method cause JdbcSQLException

  • Fix #3 EbeanInjectionListener not effect on User defined Dao

act-aaa-1.0.1

  • Fix #1 It shall not throw out NPE when AAA service cannot find the user in the system

点此查看详细信息和错误修正链接

关于AAA - ActFramework的安全框架 I - 概念及简介安全框架有哪些的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于.Net Core AA.FrameWork 应用框架介绍、AAA - ActFramework的安全框架II - 应用、ActFramework 1.0 正式发布, Java MVC 框架、ActFramework 1.0.2 发布, Java MVC 框架的相关信息,请在本站寻找。

本文标签: