首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >基于ServiceStack的无Cookieless认证

基于ServiceStack的无Cookieless认证
EN

Stack Overflow用户
提问于 2015-03-03 15:27:38
回答 1查看 252关注 0票数 2

我正在使用托管在ServiceStackV3 MVC 4项目中的ASP.NET构建REST。希望在SSL上使用HttpBasic身份验证。

我希望使用ServiceStackV3实现以下目标:

  • 无饼干认证。
  • API使用者不应该进入/auth/某样东西来进行身份验证,然后返回到/Someser性/某些操作。
  • 相反,他们直接调用/某些服务/某些行为,并传递他们的证书。

即使这意味着在每个请求中都提供用户名/密码,而无需维护任何会话或缓存。

我是否应该使用:

  • 继承BasicAuthProvider,也许是CustomUserSession?不知道我在ServiceStack的路。
  • 或者在Global.asax中实现Global.asax,检查授权头,如果凭据无效,使用Http未授权状态代码添加WWW-身份验证标头?但是,当凭据有效时,我的服务方法将如何知道它?

以下是我已经做过的事情,工作得很好,但不确定这是否是一种好方法:

(请记住,我正在/api上运行/api)

代码语言:javascript
复制
protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    //Initialize your application
    (new ServiceAppHost()).Init();
}

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
    var segments = Request.Url.Segments;
    //someone is at /api/something but metadata should be consumed by everyone
    if (segments.Length > 2 
        && segments[1] == "api/" 
        && segments[2].Replace("/", "") != "metadata")
    {
        //need to authenticate
        int UserID = -1;
        bool authorized = false;
        string authorization = Request.Headers["Authorization"];
        if (!string.IsNullOrWhiteSpace(authorization))
        {
            string[] parts = authorization.Split(' ');
            if (parts[0] == "Basic")//basic authentication
            {
                authorization = UTF8Encoding.UTF8.GetString(Convert.FromBase64String(parts[1]));
                string username = authorization.Split(':')[0], password = authorization.Split(':')[1];
                if (username == "mustermann" && password == "johndoe")
                {
                    authorized = true;
                    UserID = 13;//get from database
                    Request.Headers.Add("X-UserID", UserID + "");
                }
            }
        }

        if (!authorized)
        {
            HttpContext.Current.Items["NeedAuthenticate"] = true;
            Response.End();
        }
    }
}

void Application_EndRequest(object sender, EventArgs e)
{
    if ((bool?)HttpContext.Current.Items["NeedAuthenticate"] == true)
    {
        Response.Clear();
        Response.AddHeader("WWW-Authenticate", string.Format("Basic realm=\"{0}\"", Request.Url.Host));
        Response.SuppressContent = true;
        Response.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized;
        Response.End();
    }
}

public class MyBasicAuthProvicer : BasicAuthProvider
{
    public override bool TryAuthenticate(IServiceBase authService,
    string userName, string password)
    {
        //username & password were already validated in Global.asax
        return true;
    }
}

public class CustomUserSession : AuthUserSession
{
    //some properties of my own
    //public Kunden CurrentKunden {get;set;}

    public override void OnAuthenticated(IServiceBase authService, IAuthSession session, IAuthTokens tokens, Dictionary<string, string> authInfo)
    {
        base.OnAuthenticated(authService, session, tokens, authInfo);

        int UserID = 0;
        if (int.TryParse(authService.Request.Headers["X-UserID"], out UserID))
        {
            //get user by ID from DB and assign to CurrentKunden
            //or maybe put Kunden object in Session from Global.asax?!?
        }
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-03-03 18:36:24

我正在使用ServiceStack v4 API做类似的事情。在我的世界中,REST通过SSL使用HTTP基本凭证,只有“密码”部分(PIN #)用于身份验证。下面是我的Configure(container)方法的相关部分:

代码语言:javascript
复制
IAuthProvider authProvider = new BasicAuthProvider();
AuthFeature authFeature = new AuthFeature(
    () =>
      {
        return new AuthUserSession();
      },
    new IAuthProvider[] { authProvider }
    );
authFeature.IncludeAssignRoleServices = false;
authFeature.IncludeRegistrationService = false;
authFeature.IncludeAuthMetadataProvider = false;
Plugins.Add(authFeature);

// **** MY CUSTOM AUTH REPO
container.Register<IUserAuthRepository>(new BMSUserAuthRepository(() => dbFactory.OpenDbConnection()));

另一个妙处是,有时Session是不可访问的。这个全局过滤器确保会话可用,包括用户名、auth角色等。

代码语言:javascript
复制
// Add a request filter storing the current session in HostContext to be
// accessible from anywhere within the scope of the current request.
this.GlobalRequestFilters.Add((httpReq, httpRes, requestDTO) =>
{
    var session = httpReq.GetSession();
    RequestContext.Instance.Items.Add("Session", session);
});

最后,我的Auth存储库中有一两个片段。注意,一个正常的人会使用缓存,而不是在每个HTTP请求上查找用户的数据。

代码语言:javascript
复制
public class BMSUserAuthRepository : IUserAuthRepository
{
    private IDbConnection Db
    {
        get
        {
            return this.createDb();
        }
    }
    Func<IDbConnection> createDb;

    public BMSUserAuthRepository(Func<IDbConnection> dbConnectionFunc)
    {
        this.createDb = dbConnectionFunc;
    }

    ...

    public bool TryAuthenticate(string userName, string password, out IUserAuth userNameuserAuth)
    {
        User user = Db.Select<User>(u => /*u.UserName == userName && */ u.PIN == password).SingleOrDefault();
        if (user == null)
        {
            userNameuserAuth = new UserAuth();
            return false;
        }

        userNameuserAuth = new UserAuth()
        {
            FirstName = user.FirstName,
            LastName = user.LastName,
            Id = user.Id,
            UserName = user.UserName
        };
        return true;
    }

    public IUserAuth GetUserAuth(string userAuthId)
    {
        int id = Int32.Parse(userAuthId);
        User user = Db.SingleById<User>(id);

        List<string> roles = null;
        if (user != null) roles = Db.SqlList<string>(Db.From<Role>().Where<Role>(r => r.Id >= user.RoleId).Select(r => r.RoleName));

        return new UserAuth()
        {
            FirstName = user.FirstName,
            LastName = user.LastName,
            Id = user.Id,
            UserName = user.UserName,
            Roles = roles
        };
    }

    ...

}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28835585

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档