【问题标题】:AngularJS + Spring security remember me featureAngularJS + Spring 安全记住我功能
【发布时间】: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 登录并记住我吗?

【问题讨论】:

    标签: angularjs spring spring-security


    【解决方案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。
      猜你喜欢
      • 2013-04-09
      • 2012-03-13
      • 2015-11-06
      • 1970-01-01
      • 2012-12-04
      • 1970-01-01
      • 2016-06-23
      • 1970-01-01
      • 2014-12-26
      相关资源
      最近更新 更多