有很多方法可以做到这一点。为了让 Devise 将错误返回到我可以解释的 iPhone 应用程序(例如 401),我所做的是创建一个自定义失败应用程序:
# config/initializers/devise.rb
config.warden do |manager|
manager.failure_app = CustomFailure
end
# config/initializers/custom_failure.rb
class CustomFailure < Devise::FailureApp
def respond
unless request.format.to_sym == :html
http_auth
else
super
end
end
end
否则,无论登录信息是否正确,Devise 都只会返回带有重定向响应代码的 HTML。
由于我的应用要求用户对我的 Rails 后端进行身份验证,因此我实现了一个简单的登录系统,如下所示:
#app/controllers/pages_controller.rb
before_filter :authenticate_user!, :only => [:login]
ssl_required :login # you have to set up ssl and ssl_requirement
def login
@user = current_user
respond_to do |format|
format.html {render :text => "#{@user.id}"}
format.xml {render :text => "#{@user.id}" }
end
end
#config/routes.rb
match '/login', :to => 'pages#login'
然后在 iphone 应用程序中,您可以像这样向 /login 发送 GET 请求来验证(我使用 ASIHTTPRequest,因为它很棒):
- (void) validate_login:(NSString*)name :(NSString*)pwd
{
NSURL *login_url = [NSURL URLWithString:@"https://mysite.com/login"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:login_url];
[request setDelegate:self];
[request setUsername:name];
[request setPassword:pwd];
[request addRequestHeader:@"Accept" value:@"application/xml"];
[request startAsynchronous];
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
if ([request responseStatusCode] != 200) {
[self requestFailed:request];
}
else {
// authentication successful, store credentials
NSUSerDefaults* defaults = [NSUserDefaults standardUserDefaults];
[defaults setValue:[request username] forKey:@"username"];
[defaults setValue:[request password] forKey:@"password"];
}
}
- (void)requestFailed:(ASIHTTPRequest *)request
{
NSLog(@"failed with error: %d %@", [request responseStatusCode], [error localizedDescription]);
// tell user incorrect username/password
}
然后,当您需要将数据发布到应用程序时,您可以从用户默认值中检索用户名和密码并将它们附加到请求中。如果您需要更安全,可以将它们存储在 Keychain 中。
我确信有更好的方法可以做到这一点,但希望这可以让您思考 API 身份验证策略。