1

我想在 Java EE 服务器后端对连接到他的 iOS 应用程序的用户进行身份验证。在这里,您可以找到我的 spring 安全配置后端:

<?xml version="1.0" encoding="UTF-8"?>

<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:p="http://www.springframework.org/schema/p" 
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
             http://www.springframework.org/schema/beans/spring-beans.xsd
             http://www.springframework.org/schema/security
             http://www.springframework.org/schema/security/spring-security.xsd
             http://www.springframework.org/schema/util 
             http://www.springframework.org/schema/util/spring-util.xsd">

    <http auto-config="true" use-expressions="true">

        <intercept-url pattern="/home.mediator" access="permitAll" />
        <intercept-url pattern="/loginInvalid.security" access="permitAll" />
        <intercept-url pattern="/logout*" access="permitAll" />

        <intercept-url pattern="/user**" access="hasRole('ROLE_USER')"/>
        <intercept-url pattern="/admin**" access="hasRole('ROLE_ADMIN')"/>
        <intercept-url pattern="/*" access="isAuthenticated()" />

        <form-login login-page="/home.mediator" 
            default-target-url="/loginValid.security"
            authentication-failure-url="/loginInvalid.security" />

        <logout invalidate-session="true" 
            logout-success-url="/logoutSuccess.security" 
            logout-url="/logout.do"/>

    </http>

    <authentication-manager>
            <authentication-provider user-service-ref="customUserDetailsService">
            </authentication-provider>
    </authentication-manager>

</beans:beans>

这可以在后台 Web 应用程序的浏览器上完美运行。但问题是当我使用我的 iOS 目标 C 客户端访问我的后端 Java EE 服务器以进行如下身份验证过程时:

    NSString *login = self.loginTextField.text;
    NSString *password = self.passwordTextField.text;

    NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://localhost:8080/myJeeServer/j_spring_security_check"]];
    [request setHTTPMethod:@"POST"];
    NSString *post =[[NSString alloc] initWithFormat:@"j_username=%@&j_password=%@",login,password];
    [request setHTTPBody:[post dataUsingEncoding:NSUTF8StringEncoding]];

    NSHTTPURLResponse *urlResponse = nil;
    NSError *err;
    [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&err];
    NSLog(@"Request : %@",request);
    NSLog(@"Response : %d",urlResponse.statusCode);
    NSLog(@"Error : %d",err.code);

每次 HTTP 响应状态代码为 200 时,我都无法根据 iOS 客户端检查身份验证是成功还是失败。也许这种方式是使用 Spring 安全后端和 Objective-C 客户端前端实现身份验证的错误方式,但我没有在网上找到任何其他方式。有人可以帮我解决这个安全用例吗?使用 Objective-C 和 Spring 安全性对用户进行身份验证的最佳方法是什么?

感谢您的回答。

4

1 回答 1

0

亲爱的,

我忘了把这个老话题的解决方案放在下面,为面临同样情况的开发人员提供一种可能的解决方案:

  • 通过 HTTP 登录 iOS 客户端的示例,后面带有 spring 安全身份验证:

-(IBAction)connect:(UIButton *)sender {

        // Get login and password values
        NSString *login = self.loginTextField.text;
        NSString *password = self.passwordTextField.text;

        // Check if they are not empty before HTTP call
        if([login isEqualToString:@""] || [password isEqualToString:@""]) {
            self.loginResponse.text = @"Please select a login and a password before connect.";
            return;
        } else {
            self.userLogin = login;
            self.userPassword = password;
        }

        // Prepare request for login
        NSString *restRequest =[[NSString alloc] initWithFormat:@"%@/rest/%@",IP_SERVER,REST_LOGIN_OPERATION];
        NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL:[NSURL URLWithString:restRequest]];
        [request setHTTPMethod:@"POST"];
        NSString *post =[[NSString alloc] initWithFormat:@"j_username=%@&j_password=%@&submit=Login",self.userLogin,self.userPassword];
        [request setHTTPBody:[post dataUsingEncoding:NSUTF8StringEncoding]];

        // start the animation if it's not already going
        [self.spinner startAnimating];

        dispatch_queue_t loginQ = dispatch_queue_create("endoServerLoginQueue", NULL);
        dispatch_async(loginQ, ^(){
            // call Web Service REST on EndoServer for login
            NSHTTPURLResponse *urlResponse = nil;
            NSError *err;
            NSData *urlData =[NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&err];

            // Log async call request
            NSLog(@"[%@ %@] Request for customer login : %@",NSStringFromClass([self class]), NSStringFromSelector(_cmd), request);

            // When we have the results, use main queue to display them
            dispatch_async(dispatch_get_main_queue(), ^{

                // Parse data
                NSString *str=[[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];

                // Log async call response
                NSLog(@"[%@ %@] Response status code for doctor login : %d",NSStringFromClass([self class]), NSStringFromSelector(_cmd), urlResponse.statusCode);
                NSLog(@"[%@ %@] Response body for doctor login : (doctor id = %@)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), str);
                NSLog(@"[%@ %@] Error code for doctor login : %d",NSStringFromClass([self class]), NSStringFromSelector(_cmd), err.code);

                if(urlResponse.statusCode == 200) {

                    [self.logoutButton setEnabled:YES];

                    NSLog(@"[%@ %@] Connection Success for Customer login (%@) and Password (%@).",NSStringFromClass([self class]), NSStringFromSelector(_cmd), self.userLogin,self.userPassword);


                    // Save login and password in user preferences
                    NSUserDefaults *userPreferences = [NSUserDefaults standardUserDefaults];
                    [userPreferences setObject:self.userLogin forKey:USER_LOGIN_KEY];
                    [userPreferences setObject:self.userPassword forKey:USER_PASSWORD_KEY];
                    [userPreferences setInteger:[str integerValue] forKey:USER_ID_KEY];
                    [userPreferences synchronize];

                    // Go to Home screen view
                    str = [NSString stringWithFormat:@"Welcome %@ ! ",self.userLogin];
                    [self performSegueWithIdentifier:@"goToHomePage" sender:self];
                }

                if(err.code == -1004) {
                    str = @"Server is shutdown, please try later or contact administrator.";
                    NSLog(@"[%@ %@] Error message : %@",NSStringFromClass([self class]), NSStringFromSelector(_cmd), str);
                }

                self.loginResponse.text = str; // makes UIKit calls, so must be main thread
                [self.spinner stopAnimating]; // stop the animation
            });
        });

}

  • 带有自定义身份验证处理程序的 spring 安全配置示例:

    ......

    <context:annotation-config />
    <context:component-scan base-package="com....." />
    
    ....
    
    <!-- 
        Add Rest API access for mobile devices
     -->
    <http pattern="/rest/**" entry-point-ref="authenticationEntryPoint" use-expressions="true">
        <intercept-url pattern="/rest/login" access="hasRole('ROLE_CUSTOMER')" />
        <intercept-url pattern="/rest/customer/**" access="hasRole('ROLE_CUSTOMER')"/>
        <intercept-url pattern="/rest/logout" access="isAuthenticated()" />
        <form-login login-processing-url="/rest/login"
                    authentication-success-handler-ref="customAuthenticationSuccessHandler"
                    authentication-failure-handler-ref="customAuthenticationFailureHandler"/>
        <logout success-handler-ref="customLogoutSuccessHandler" logout-url="/rest/logout" invalidate-session="true"/>
    </http>
    
    
    ....
    

和处理程序实现示例:

@Component(value = "customAuthenticationSuccessHandler")
public class CustomAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

    private static final Logger LOGGER = Logger.getLogger(CustomAuthenticationSuccessHandler.class);

    @Autowired
    private IUserRepository userRepository;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
            HttpServletResponse response, Authentication authentication)
                    throws IOException, ServletException {
        if (hasRoleCustomer(authentication)) {
            String username = authentication.getName();
            User user = userRepository.findByUsername(username);
            response.setStatus(HttpServletResponse.SC_OK);
            response.getWriter().print(user.getId());
            LOGGER.info("Authentication Success for customer : "+user.getUsername()+", with id : "+user.getId());
        } else {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().print("Access Denied, please contact the administrator.");
            LOGGER.info("Access denied for customer : "+authentication.getName());
        }
        response.getWriter().flush();
    }

其他所需的处理程序应根据您的业务需求以相同的方式实现。

于 2017-11-11T02:08:37.837 回答