AngularJS + Spring 安全记住我功能
Posted
技术标签:
【中文标题】AngularJS + Spring 安全记住我功能【英文标题】:AngularJS + Spring security remember me feature 【发布时间】:2017-08-10 18:17:57 【问题描述】:我正在做基于 spring boot + Angularjs 的应用程序 我根据这篇博文进行的身份验证:https://spring.io/guides/tutorials/spring-security-and-angular-js/ 所以我启用了基本用户/密码或 OAuth2
我想向它添加记住我的功能。我有 AuthService
AuthService.authenticate = function (credentials, callback)
var headers = credentials ?
authorization: "Basic "
+ btoa(credentials.username + ":" + credentials.password)
: ;
$http.get('api/user/', headers: headers, timeout: 5000).then(
function (response)
var data = response.data;
if (data.id)
$rootScope.authenticated = true;
$rootScope.principal = data;
$translate.use($rootScope.principal.language);
$location.search('lang', $rootScope.principal.language);
AvatarService.getUserAvatar($rootScope.principal);
$log.debug("[DEBUG] User logged in " + $rootScope.principal.id);
else
$rootScope.authenticated = false;
callback && callback();
,
function ()
$rootScope.authenticated = false;
callback && callback();
);
;
在登录控制器中我得到了处理:
$scope.credentials = ;
//LOGIN
$scope.login = function ()
AuthService.authenticate($scope.credentials, function ()
if ($rootScope.authenticated)
$location.path("/");
AlertService.clearAlerts();
else
$location.path("/login");
AlertService.addError('user.login.failed');
);
;
在 Spring 安全性上,我像往常一样设置它,(配置的一部分)
....
.and().formLogin()
.loginPage("/#/login")
.and().rememberMe()
.rememberMeServices(rememberMeServices())
.key("remember-me-key")
.and().addFilterBefore(new CsrfHeaderFilter(), CsrfFilter.class)
.csrf()
....
但我的猜测是它期望使用记住我而不是基本身份验证的后调用
如何调整它才能使用记住我? 我可以通过帖子执行调用以使用 j_username j_password 登录并记住我吗?
【问题讨论】:
【参考方案1】:我也在开发 Spring + Angular2 应用程序。就我而言,后端返回 2 个令牌(访问令牌和刷新令牌)。之后,我在每个请求的标题中添加“授权”:“Bearer”+this.accessToken。
【讨论】:
【参考方案2】:您可以配置 Spring Boot 服务器以将身份验证令牌发回给客户端。在客户端(Angular)中,将令牌保存在某处(本地存储/cookie)。然后您可以在应用首次加载时检查令牌的存在。 JWT 令牌在处理 Web 客户端身份验证时非常有用。
例如,如果我的安全配置文件中有这段代码。
.authorizeRequests()
.antMatchers("/", "/index.html", "/login.html", "/home.html").permitAll()
.anyRequest()
.authenticated().and()
.formLogin()
.successHandler(authenticationSuccessHandler)
.failureHandler(authenticationFailureHandler)
我可以轻松实现authenticationSuccessHandler
并在成功登录后向用户发出一个身份验证令牌或身份验证cookie,或两者都返回给用户。
public class AuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler
... bla bla bla
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication ) throws IOException, ServletException
clearAuthenticationAttributes(request);
User user = (User)authentication.getPrincipal();
String jws = tokenHelper.generateToken( user.getUsername() );
// cookie in response
Cookie authCookie = new Cookie( TOKEN_COOKIE, ( jws ) );
authCookie.setPath( "/" );
authCookie.setHttpOnly( true );
authCookie.setMaxAge( EXPIRES_IN );
response.addCookie( authCookie );
// token in response
UserTokenState userTokenState = new UserTokenState(jws, EXPIRES_IN);
String jwtResponse = objectMapper.writeValueAsString( userTokenState );
response.setContentType("application/json");
response.getWriter().write( jwtResponse );
更多详情请见springboot-jwt-starter。这是一个使用 Spring Boot 和 AngularJS 的入门工具包项目。
如果您想使用 Angular 实现 Spring Boot 安全性,The Login Page: Angular JS and Spring Security Part II 系列是一本非常好的阅读材料。
【讨论】:
The Login Page: Angular JS and Spring Security Part II 完全基于我所做的应用程序,因此我得到了覆盖。将很快使用身份验证令牌检查解决方案 springboot-jwt-starter 基于“登录页面:Angular JS 和 Spring Security Part II”,但它不使用会话,而是使用 JWT(JSON Web 令牌)。如果您还有其他问题,请告诉我。 谢谢。根据您的 github 代码,我能够调整我的应用程序,使其使用令牌并将其保存 1 周。适用于普通和誓言登录 亲爱的,我很高兴听到我的代码有帮助。你介意给它一个星号来支持 github 代码吗? 当然 :) 一句话:在 TokenFilter 上,每个请求都会对 DB 进行查询,这在性能方面并不好。在我的应用程序中,我添加了会话(从配置中删除了无状态),并且仅当 SecurityContextHolder.getContext().getAuthentication() 或 instanceof AnonAuthentication 时才从数据库中获取令牌值和帐户。作为额外的好处,auth 有当前帐户,调用 whoami 时可以直接返回。同样在我的应用程序中,我将整个主体存储在 angular $rootContext.principal 中。这样就可以读取所有信息,如 mail 、 id 或 avatar id ,而无需对后端进行额外查询【参考方案3】:您可以使用带有 Angular 和基本身份验证的 Spring remember-me 服务,您必须在帖子中发送 remember-me 参数。
下面是 Angular2 的示例:
import Injectable from "@angular/core";
import HttpClient, HttpHeaders, HttpParams from "@angular/common/http";
import Observable from "rxjs/Observable";
import CSRF_URL, LOGIN_URL, LOGOUT_URL from "./auth.constant";
export interface RespAccess
email?: String;
name: string;
permissions: [string];
@Injectable()
export class AuthenticationService
constructor(private http: HttpClient)
login(username: string, password: string, rememberme: boolean): Observable<RespAccess>
let headers = new HttpHeaders();
headers = headers.append('Authorization', 'Basic ' + btoa(username + ':' + password));
headers = headers.append('X-Requested-With', 'XMLHttpRequest'); // to suppress 401 browser popup
const params = new HttpParams().append('remember-me', (rememberme ? 'true' : 'false' ));
return this.http.post<RespAccess>(LOGIN_URL,'', headers, params);
logout() : Observable<any>
return this.http.post<any>(LOGOUT_URL, '');
getCSRFToken()
this.http.get<any>(CSRF_URL) // /api/auth/csrf
.subscribe();
如果您使用 CSRF 保护,您必须在登录前获取 CSRF 令牌。您可以简单地访问返回令牌的不安全 url,这是 Spring 服务器端控制器中的方法:
@RequestMapping("/api/auth/csrf")
public CsrfToken csrf(CsrfToken token)
return token;
【讨论】:
嗨@Carlos Cuesta,即使记住我的参数是假的,也会创建cookie。以上是关于AngularJS + Spring 安全记住我功能的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot - 具有安全性的 Angularjs $stateProvider
使用 angularjs 使用安全的 spring rest 服务