Android 设备针对 Spring 安全休息 API 的身份验证
Authentification from Android Device against Spring Security Rest API
我有一个带有 REST-API 的 SPRING 后端。它由用户名和密码保护。当我首先用我的电脑浏览器打开它时,会显示登录屏幕,在我添加凭据后,我可以流畅地访问 api。
当我通过 Android APP 尝试同样的操作时,我每次都会看到登录屏幕。要在 Android 端进行身份验证,我使用默认情况下可访问的 REST API 请求。
内部 Android 应用程序浏览器是否不兼容存储会话 cookie?每次创建新的 HTTP 会话时。我正在使用 Volley 处理请求
弹簧-security.xml
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/api/user/login" access="permitAll" /> <!--IS_AUTHENTICATED_ANONYMOUSLY-->
<intercept-url pattern="/admin/**" access="hasAnyRole('ROLE_ADMIN','ROLE_GROUP_LEADER')" />
<intercept-url pattern="/api/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN','ROLE_GROUP_LEADER')" />
<form-login
login-page="/login"
default-target-url="/admin"
authentication-failure-url="/login?error"
username-parameter="username"
password-parameter="password"
/>
<access-denied-handler error-page="/403" />
<logout logout-success-url="/login?logout" />
</http>
<authentication-manager alias="authManager">
<authentication-provider >
<password-encoder ref="encoder" />
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query=
"select username,password, enabled from user where username=?"
authorities-by-username-query=
"select username, name as role from role r,user u where u.role_id = r.id and username =? " />
</authentication-provider>
</authentication-manager>
其余控制器中的代码api
UserDetails userDetails = userDetailsSvc.loadUserByUsername(user.getUsername());
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(userDetails, "123",userDetails.getAuthorities());
Authentication authentication = authManager.authenticate(token);
log.debug("Logging in with [{}]", authentication.getPrincipal());
SecurityContext securityContext = SecurityContextHolder.getContext();
securityContext.setAuthentication(authentication);
HttpSession session = request.getSession(true);
session.setAttribute("SPRING_SECURITY_CONTEXT", securityContext);
Spring 安全调试
************************************************************
Request received for POST '/api/user/create':
org.apache.catalina.connector.RequestFacade@36dc8ced
servletPath:/api/user/create
pathInfo:null
headers:
if-modified-since: Sat, 03 Jan 2015 12:35:50 GMT+00:00
content-type: application/json; charset=utf-8
user-agent: Dalvik/1.6.0 (Linux; U; Android 4.0.4; GT-P7100 Build/IMM76D)
host: 192.168.178.36:8088
connection: Keep-Alive
accept-encoding: gzip
content-length: 124
Security filter chain: [
SecurityContextPersistenceFilter
WebAsyncManagerIntegrationFilter
LogoutFilter
UsernamePasswordAuthenticationFilter
BasicAuthenticationFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
]
************************************************************
2015-01-03 13:53:46 INFO Spring Security Debugger:39 -
************************************************************
New HTTP session created: A430DD754F7F6E466D07B10D1DDCCEF7
Call stack:
at org.springframework.security.web.debug.Logger.info(Logger.java:29)
at org.springframework.security.web.debug.DebugRequestWrapper.getSession(DebugFilter.java:144)
at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:238)
at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:238)
at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:238)
at org.springframework.security.web.savedrequest.HttpSessionRequestCache.saveRequest(HttpSessionRequestCache.java:40)
at org.springframework.security.web.access.ExceptionTranslationFilter.sendStartAuthentication(ExceptionTranslationFilter.java:184)
at org.springframework.security.web.access.ExceptionTranslationFilter.handleSpringSecurityException(ExceptionTranslationFilter.java:168)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:131)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:150)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.springframework.security.web.debug.DebugFilter.invokeWithWrappedRequest(DebugFilter.java:70)
at org.springframework.security.web.debug.DebugFilter.doFilter(DebugFilter.java:59)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:136)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:74)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:516)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1015)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:652)
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1575)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1533)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:722)
************************************************************
2015-01-03 13:53:46 INFO Spring Security Debugger:39 -
************************************************************
Request received for GET '/login':
org.apache.catalina.connector.RequestFacade@36dc8ced
servletPath:/login
pathInfo:null
headers:
if-modified-since: Sat, 03 Jan 2015 12:35:50 GMT+00:00
content-type: application/json; charset=utf-8
user-agent: Dalvik/1.6.0 (Linux; U; Android 4.0.4; GT-P7100 Build/IMM76D)
host: 192.168.178.36:8088
connection: Keep-Alive
accept-encoding: gzip
Security filter chain: [
SecurityContextPersistenceFilter
WebAsyncManagerIntegrationFilter
LogoutFilter
UsernamePasswordAuthenticationFilter
BasicAuthenticationFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
]
************************************************************
MonitorFilter::WARNING: the monitor filter must be the first filter in the chain.
齐射
CookieManager manager = new CookieManager();
CookieHandler.setDefault( manager );
mQueue = Volley.newRequestQueue(context);
我怀疑问题可能是您正在实施自己的自定义身份验证控制器端点,而不是使用完整的 spring-security 链。
根据您的 xml 配置,普通过滤器链仍将在所有请求上被调用,但仅通过调用控制器中的 authenticate() 方法就可以做到这一点,而不是其余的身份验证成功处理程序的东西,例如您实际上不会在使用临时控制器身份验证的响应中设置 cookie)
最简单的测试方法就是直接curl url,或者使用像postman(chrome plugin for rest apis)之类的东西来测试api 身份验证端点并查看是否在响应中设置了任何 cooke。
如果您可以控制服务器端代码(例如,您可以更改它而不仅仅是在 android 应用程序上工作),这里有一些想法:
我会避免自定义身份验证端点并尝试 hand-roll 安全方面的东西 - spring 安全方面真的很擅长这些东西。
假设您不想使用 oauth 以及 API 的解决方案的复杂性,那么请查看 Google's recommended approach for securing APIs for mobile apps。它与您采用的方法类似,但对于登录,您只需在 android 应用程序中嵌入一个 Web 视图,并使用它让用户直接登录标准 spring 安全表单(所以开始利用 Spring-security 默认行为,例如 cookie 等),然后在应用程序中,您只需从网络响应中获取用户令牌,然后存储它 - 然后可以在所有 API 请求中作为请求 header(因此用户不必继续登录移动应用程序)
我在这里概述了该方法:
Securing your API for mobile access
并在这里也整合了 spring 安全实施。
尝试了你的建议并成功了。
在我检查过后端传输所需的 cookie 之后,我调整了 volley 以便它存储传输的 cookie 并在之后的每个请求中将其作为令牌重新传输。 cookie 存储在首选项中。
public GsonRequest(...)
.....
if(PreferencesManager.getInstance().getSessionCookie()!=null)
this.headers.put("Cookie", "JSESSIONID="+ PreferencesManager.getInstance().getSessionCookie());
@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
String cookie = MyApp.get().checkSessionCookie(response.headers);
PreferencesManager.getInstance().setSessionCookie(cookie);
.....
}
如 vmirinov 在 go here 上所述,稍作修改
public final String checkSessionCookie(Map<String, String> headers) {
if (headers.containsKey(SET_COOKIE_KEY)
&& headers.get(SET_COOKIE_KEY).toLowerCase().contains(SESSION_COOKIE)) {
String cookie = headers.get(SET_COOKIE_KEY);
if (cookie.length() > 0) {
String[] splitCookie = cookie.split(";");
String[] splitSessionId = splitCookie[0].split("=");
cookie = splitSessionId[1];
SharedPreferences.Editor prefEditor = _preferences.edit();
prefEditor.putString(SESSION_COOKIE, cookie);
prefEditor.commit();
return cookie;
}
}
return "";
}
我有一个带有 REST-API 的 SPRING 后端。它由用户名和密码保护。当我首先用我的电脑浏览器打开它时,会显示登录屏幕,在我添加凭据后,我可以流畅地访问 api。
当我通过 Android APP 尝试同样的操作时,我每次都会看到登录屏幕。要在 Android 端进行身份验证,我使用默认情况下可访问的 REST API 请求。 内部 Android 应用程序浏览器是否不兼容存储会话 cookie?每次创建新的 HTTP 会话时。我正在使用 Volley 处理请求
弹簧-security.xml
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/api/user/login" access="permitAll" /> <!--IS_AUTHENTICATED_ANONYMOUSLY-->
<intercept-url pattern="/admin/**" access="hasAnyRole('ROLE_ADMIN','ROLE_GROUP_LEADER')" />
<intercept-url pattern="/api/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN','ROLE_GROUP_LEADER')" />
<form-login
login-page="/login"
default-target-url="/admin"
authentication-failure-url="/login?error"
username-parameter="username"
password-parameter="password"
/>
<access-denied-handler error-page="/403" />
<logout logout-success-url="/login?logout" />
</http>
<authentication-manager alias="authManager">
<authentication-provider >
<password-encoder ref="encoder" />
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query=
"select username,password, enabled from user where username=?"
authorities-by-username-query=
"select username, name as role from role r,user u where u.role_id = r.id and username =? " />
</authentication-provider>
</authentication-manager>
其余控制器中的代码api
UserDetails userDetails = userDetailsSvc.loadUserByUsername(user.getUsername());
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(userDetails, "123",userDetails.getAuthorities());
Authentication authentication = authManager.authenticate(token);
log.debug("Logging in with [{}]", authentication.getPrincipal());
SecurityContext securityContext = SecurityContextHolder.getContext();
securityContext.setAuthentication(authentication);
HttpSession session = request.getSession(true);
session.setAttribute("SPRING_SECURITY_CONTEXT", securityContext);
Spring 安全调试
************************************************************
Request received for POST '/api/user/create':
org.apache.catalina.connector.RequestFacade@36dc8ced
servletPath:/api/user/create
pathInfo:null
headers:
if-modified-since: Sat, 03 Jan 2015 12:35:50 GMT+00:00
content-type: application/json; charset=utf-8
user-agent: Dalvik/1.6.0 (Linux; U; Android 4.0.4; GT-P7100 Build/IMM76D)
host: 192.168.178.36:8088
connection: Keep-Alive
accept-encoding: gzip
content-length: 124
Security filter chain: [
SecurityContextPersistenceFilter
WebAsyncManagerIntegrationFilter
LogoutFilter
UsernamePasswordAuthenticationFilter
BasicAuthenticationFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
]
************************************************************
2015-01-03 13:53:46 INFO Spring Security Debugger:39 -
************************************************************
New HTTP session created: A430DD754F7F6E466D07B10D1DDCCEF7
Call stack:
at org.springframework.security.web.debug.Logger.info(Logger.java:29)
at org.springframework.security.web.debug.DebugRequestWrapper.getSession(DebugFilter.java:144)
at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:238)
at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:238)
at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:238)
at org.springframework.security.web.savedrequest.HttpSessionRequestCache.saveRequest(HttpSessionRequestCache.java:40)
at org.springframework.security.web.access.ExceptionTranslationFilter.sendStartAuthentication(ExceptionTranslationFilter.java:184)
at org.springframework.security.web.access.ExceptionTranslationFilter.handleSpringSecurityException(ExceptionTranslationFilter.java:168)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:131)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:150)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.springframework.security.web.debug.DebugFilter.invokeWithWrappedRequest(DebugFilter.java:70)
at org.springframework.security.web.debug.DebugFilter.doFilter(DebugFilter.java:59)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:136)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:74)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:516)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1015)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:652)
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1575)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1533)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:722)
************************************************************
2015-01-03 13:53:46 INFO Spring Security Debugger:39 -
************************************************************
Request received for GET '/login':
org.apache.catalina.connector.RequestFacade@36dc8ced
servletPath:/login
pathInfo:null
headers:
if-modified-since: Sat, 03 Jan 2015 12:35:50 GMT+00:00
content-type: application/json; charset=utf-8
user-agent: Dalvik/1.6.0 (Linux; U; Android 4.0.4; GT-P7100 Build/IMM76D)
host: 192.168.178.36:8088
connection: Keep-Alive
accept-encoding: gzip
Security filter chain: [
SecurityContextPersistenceFilter
WebAsyncManagerIntegrationFilter
LogoutFilter
UsernamePasswordAuthenticationFilter
BasicAuthenticationFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
]
************************************************************
MonitorFilter::WARNING: the monitor filter must be the first filter in the chain.
齐射
CookieManager manager = new CookieManager();
CookieHandler.setDefault( manager );
mQueue = Volley.newRequestQueue(context);
我怀疑问题可能是您正在实施自己的自定义身份验证控制器端点,而不是使用完整的 spring-security 链。
根据您的 xml 配置,普通过滤器链仍将在所有请求上被调用,但仅通过调用控制器中的 authenticate() 方法就可以做到这一点,而不是其余的身份验证成功处理程序的东西,例如您实际上不会在使用临时控制器身份验证的响应中设置 cookie)
最简单的测试方法就是直接curl url,或者使用像postman(chrome plugin for rest apis)之类的东西来测试api 身份验证端点并查看是否在响应中设置了任何 cooke。
如果您可以控制服务器端代码(例如,您可以更改它而不仅仅是在 android 应用程序上工作),这里有一些想法:
我会避免自定义身份验证端点并尝试 hand-roll 安全方面的东西 - spring 安全方面真的很擅长这些东西。
假设您不想使用 oauth 以及 API 的解决方案的复杂性,那么请查看 Google's recommended approach for securing APIs for mobile apps。它与您采用的方法类似,但对于登录,您只需在 android 应用程序中嵌入一个 Web 视图,并使用它让用户直接登录标准 spring 安全表单(所以开始利用 Spring-security 默认行为,例如 cookie 等),然后在应用程序中,您只需从网络响应中获取用户令牌,然后存储它 - 然后可以在所有 API 请求中作为请求 header(因此用户不必继续登录移动应用程序)
我在这里概述了该方法:
Securing your API for mobile access
并在这里也整合了 spring 安全实施。
尝试了你的建议并成功了。
在我检查过后端传输所需的 cookie 之后,我调整了 volley 以便它存储传输的 cookie 并在之后的每个请求中将其作为令牌重新传输。 cookie 存储在首选项中。
public GsonRequest(...)
.....
if(PreferencesManager.getInstance().getSessionCookie()!=null)
this.headers.put("Cookie", "JSESSIONID="+ PreferencesManager.getInstance().getSessionCookie());
@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
String cookie = MyApp.get().checkSessionCookie(response.headers);
PreferencesManager.getInstance().setSessionCookie(cookie);
.....
}
如 vmirinov 在 go here 上所述,稍作修改
public final String checkSessionCookie(Map<String, String> headers) {
if (headers.containsKey(SET_COOKIE_KEY)
&& headers.get(SET_COOKIE_KEY).toLowerCase().contains(SESSION_COOKIE)) {
String cookie = headers.get(SET_COOKIE_KEY);
if (cookie.length() > 0) {
String[] splitCookie = cookie.split(";");
String[] splitSessionId = splitCookie[0].split("=");
cookie = splitSessionId[1];
SharedPreferences.Editor prefEditor = _preferences.edit();
prefEditor.putString(SESSION_COOKIE, cookie);
prefEditor.commit();
return cookie;
}
}
return "";
}