当前位置: 移动技术网 > IT编程>开发语言>.net > asp.net core 自定义 Policy 替换 AllowAnonymous 的行为

asp.net core 自定义 Policy 替换 AllowAnonymous 的行为

2019年11月21日  | 移动技术网IT编程  | 我要评论

建宁莲子,红玉西瓜,龙膜官网

asp.net core 自定义 policy 替换 allowanonymous 的行为

intro

最近对我们的服务进行了改造,原本内部服务在内部可以匿名调用,现在增加了限制,通过 identity server 来管理 api 和 client,网关和需要访问api的客户端或api服务相互调用通过 client_credencial 的方式来调用,这样一来我们可以清晰知道哪些 api 服务会被哪些 api/client 所调用,而且安全性来说更好。
为了保持后端服务的代码更好的兼容性,希望能够实现相同的代码通过在 startup 里不同的配置实现不同的 authorization 逻辑,原来我们的服务的 authorize 都是以 authorize("policyname") 的形式来写的,这样一来我们只需要修改这个 policy 的授权配置就可以了。对于 allowanonymous 就希望可以通过一种类似的方式来实现,通过自定义一个 policy 来实现自己的逻辑

实现方式

将 action 上的 allowanonymous 替换为 authorize("policyname"),在没有设置 authorize 的 controller 上增加 authorize("policyname")

public class allowanonymouspolicytransformer : iapplicationmodelconvention
{
    private readonly string _policyname;

    public allowanonymouspolicytransformer() : this("anonymous")
    {
    }

    public allowanonymouspolicytransformer(string policyname) => _policyname = policyname;

    public void apply(applicationmodel application)
    {
        foreach (var controllermodel in application.controllers)
        {
            if (controllermodel.filters.any(_ => _.gettype() == typeof(authorizefilter)))
            {
                foreach (var actionmodel in controllermodel.actions)
                {
                    if (actionmodel.filters.any(_ => _.gettype() == typeof(allowanonymousfilter)))
                    {
                        var allowanonymousfilter = actionmodel.filters.first(_ => _.gettype() == typeof(allowanonymousfilter));
                        actionmodel.filters.remove(allowanonymousfilter);
                        actionmodel.filters.add(new authorizefilter(_policyname));
                    }
                }
            }
            else
            {
                if (controllermodel.filters.any(_ => _.gettype() == typeof(allowanonymousfilter)))
                {
                    var allowanonymousfilter = controllermodel.filters.first(_ => _.gettype() == typeof(allowanonymousfilter));
                    controllermodel.filters.remove(allowanonymousfilter);
                }
                controllermodel.filters.add(new authorizefilter(_policyname));
            }
        }
    }
}

public static class mvcbuilderextensions
{
    public static imvcbuilder addanonymouspolicytransformer(this imvcbuilder builder)
    {
        builder.services.configure<mvcoptions>(options =>
        {
            options.conventions.insert(0, new allowanonymouspolicytransformer());
        });
        return builder;
    }

    public static imvcbuilder addanonymouspolicytransformer(this imvcbuilder builder, string policyname)
    {
        builder.services.configure<mvcoptions>(options =>
        {
            options.conventions.insert(0, new allowanonymouspolicytransformer(policyname));
        });
        return builder;
    }
}

controller 中的代码:

[route("api/[controller]")]
public class valuescontroller : controller
{
    private readonly ilogger _logger;

    public valuescontroller(ilogger<valuescontroller> logger)
    {
        _logger = logger;
    }

    // get api/values
    [httpget]
    public actionresult<ienumerable<string>> get()
    {
        var msg = $"isauthenticated: {user.identity.isauthenticated} ,username: {user.identity.name}";
        _logger.loginformation(msg);
        return new string[] { msg };
    }

    // get api/values/5
    [authorize]
    [httpget("{id:int}")]
    public actionresult<string> get(int id)
    {
        return "value";
    }
    // ...
}

startup 中 configureservices 配置:

var anonymouspolicyname = "anonymous";

services.addauthorization(options =>
{
    options.addpolicy(anonymouspolicyname, builder => builder.requireassertion(context => context.user.identity.isauthenticated));

    options.defaultpolicy = new authorizationpolicybuilder(headerauthenticationdefaults.authenticationschema)
        .requireauthenticateduser()
        .requireassertion(context => context.user.getuserid<int>() > 0)
        .build();
});

services.addmvc(options =>
    {
        options.conventions.add(new apicontrollerversionconvention());
    })
    .addanonymouspolicytransformer(anonymouspolicyname)
    ;

实现效果

访问原来的匿名接口

with custom anonymous policy

userid 为0访问原来的匿名接口

with header authentication && userid <= 0

userid 大于0访问原来的匿名接口

with header authentication && userid > 0

userid 为0访问需要登录的接口
with header authentication && userid <= 0 && userid >0 required

userid 大于0访问需要登录的接口
with header authentication && userid > 0 && userid >0 required

more

注:按照上面的做法已经可以做到自定义 policy 代替 allowanonymous 的行为,但是原来返回的401,现在可能返回到就是 403 了

reference

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网