当前位置:网站首页>Solon Auth 认证框架使用演示(更简单的认证框架)

Solon Auth 认证框架使用演示(更简单的认证框架)

2022-07-05 05:13:00 林西东

最近看了好几个认证框架,什么 Appache Shiro 啦、Sa-Token 啦、Spring Security啦。。。尤其是Spring Security,做为对标 Spring Boot & Cloud 的框架 Solon 怎么的也要有自己的亲生安全认证框架。所以在适配了 Sa-Token(satoken-solon-plugin) 和 sureness(sureness-solon-plugin) 之后,也开发了Solon 的亲儿子:Solon Auth (solon.auth)。设计目标是更加简单些、更直接些,同时为用户提供更丰富而不同的认证框架选择。

Solon Auth (solon.auth)

Solon Auth 的定位是,只做认证控制。侧重对验证结果的适配,及在此基础上的统一控制和应用。功能会少,但适配起来不会晕。

Solon Auth 支持规则控制和注解控制两种方案,各有优缺点,也可组合使用:

  • 规则控制,适合在一个地方进行整体的宏观控制
  • 注解控制,方便在细节处精准把握

一、开始适配,完成2步动作即可

  • 第1步,构建一个认证适配器
@Configurationpublic class Config {    @Bean    public AuthAdapter init() {        //        // 构建适配器        //        return new AuthAdapter()                .loginUrl("/login") //设定登录地址,未登录时自动跳转(如果不设定,则输出401错误)                .addRule(r -> r.include("**").verifyIp().failure((c, t) -> c.output("你的IP不在白名单"))) //添加规则                .addRule(b -> b.exclude("/login**").exclude("/run/**").verifyPath()) //添加规则                .processor(new AuthProcessorImpl()) //设定认证处理器                .failure((ctx, rst) -> { //设定默认的验证失败处理                    ctx.render(rst);                });    }}//规则配置说明//1.include(path) 规则包函的路径范围,可多个//2.exclude(path) 规则排序的路径池围,可多个//3.failure(..)   规则失则后的处理//4.verifyIp()... 规则要做的验证方案(可多个不同的验证方案)
  • 第2步,实现一个认证处理器

先了解一下 AuthProcessor 的接口,它对接的是一系列的验证动作结果。可能用户得自己也得多干点活,但很直观。

//认证处理器public class AuthProcessorImpl implements AuthProcessor {    @Override    public boolean verifyIp(String ip) {        //验证IP,是否有权访问    }    @Override    public boolean verifyLogined() {        //验证登录状态,用户是否已登录    }    @Override    public boolean verifyPath(String path, String method) {        //验证路径,用户可访问    }    @Override    public boolean verifyPermissions(String[] permissions, Logical logical) {        //验证特定权限,用户是权有限    }    @Override    public boolean verifyRoles(String[] roles, Logical logical) {        //验证特定角色,用户是否角色    }}

现在做一次适配实战,用的是一份生产环境的代码:

public class GritAuthProcessor implements AuthProcessor {    /**     * 获取主体Id     * */    protected long getSubjectId() {        return SessionBase.global().getSubjectId();    }    /**     * 获取主体显示名     */    protected String getSubjectDisplayName() {        return SessionBase.global().getDisplayName();    }    @Override    public boolean verifyIp(String ip) {        //安装模式,则忽略        if (Solon.cfg().isSetupMode()) {            return true;        }        long subjectId = getSubjectId();        if (subjectId > 0) {            String subjectDisplayName = getSubjectDisplayName();            Context ctx = Context.current();            if (ctx != null) {                //old                ctx.attrSet("user_puid", String.valueOf(subjectId));                ctx.attrSet("user_name", subjectDisplayName);                //new                ctx.attrSet("user_id", String.valueOf(subjectId));                ctx.attrSet("user_display_name", subjectDisplayName);            }        }        //非白名单模式,则忽略        if (Solon.cfg().isWhiteMode() == false) {            return true;        }        return CloudClient.list().inListOfClientAndServerIp(ip);    }    @Override    public boolean verifyLogined() {        //安装模式,则忽略        if (Solon.cfg().isSetupMode()) {            return true;        }        return getSubjectId() > 0;    }    @Override    public boolean verifyPath(String path, String method) {        //安装模式,则忽略        if (Solon.cfg().isSetupMode()) {            return true;        }        try {            if (GritClient.global().resource().hasResourceByUri(path) == false) {                return true;            } else {                return GritClient.global().auth().hasUri(getSubjectId(), path);            }        } catch (SQLException e) {            throw new GritException(e);        }    }    @Override    public boolean verifyPermissions(String[] permissions, Logical logical) {        long subjectId = getSubjectId();        try {            if (logical == Logical.AND) {                boolean isOk = true;                for (String p : permissions) {                    isOk = isOk && GritClient.global().auth().hasPermission(subjectId, p);                }                return isOk;            } else {                for (String p : permissions) {                    if (GritClient.global().auth().hasPermission(subjectId, p)) {                        return true;                    }                }                return false;            }        } catch (Exception e) {            throw new RuntimeException(e);        }    }    @Override    public boolean verifyRoles(String[] roles, Logical logical) {        long subjectId = getSubjectId();        try {            if (logical == Logical.AND) {                boolean isOk = true;                for (String r : roles) {                    isOk = isOk && GritClient.global().auth().hasRole(subjectId, r);                }                return isOk;            } else {                for (String r : roles) {                    if (GritClient.global().auth().hasRole(subjectId, r)) {                        return true;                    }                }                return false;            }        } catch (Exception e) {            throw new RuntimeException(e);        }    }}

二、2种应用方式(一般组合使用)

刚才我们算是适配好了,现在就应用的活了。

  • 第1种,在 AuthAdapter 直接配置所有规则,或部分规则(也可以不配)
//参考上面的适配器 addRule(...)

配置的好处是,不需要侵入业务代码;同时在统一的地方,宏观可见;但容易忽略掉细节。

  • 第2种,基于注解做一部份(一般特定权限 或 特定角色时用)
@Mapping("/rock/agroup")@Controllerpublic class AgroupController {    @Mapping("")    public void home() {        //agroup 首页    }    @Mapping("inner")    public void inner() {        //内部列表页    }        @AuthPermissions("agroup:edit") //需要特定权限    @Mapping("edit/{id}")    public void edit(int id) {        //编辑显示页,需要编辑权限    }    @AuthRoles("admin")  //需要特定角色    @Mapping("edit/{id}/ajax/save")    public void save(int id) {        //编辑处理接口,需要管理员权限    }}

注解的好处是,微观可见,在一个方法上就可以看到它需要什么权限或角色,不容易忽略。

  • 组合使用方式

一般,用配置规则,控制所有需要登录的地址;用注解,控制特定的权限或角色。

三、本案源码

https://gitee.com/noear/solon_demo/tree/master/demo16.solon_auth

四、其它生产项目应用

https://gitee.com/noear/water/tree/master/wateradmin

https://gitee.com/noear/sponge/tree/main/spongeadmin

附:Solon 项目地址

附:Solon 其它入门示例

原网站

版权声明
本文为[林西东]所创,转载请带上原文链接,感谢
https://my.oschina.net/noear/blog/5074904