Рубрики
Без рубрики

Весенняя страница входа безопасности с Angular

Узнайте, как реализовать страницу входа в систему Spring Security с помощью Angular.

Автор оригинала: baeldung.

1. Обзор

В этом учебнике мы будем создавать Страница входа с помощью Spring Security с:

  • Угловые
  • Угловые 2, 4, 5 и 6

Пример приложения, которое мы собираемся обсудить здесь, состоит из клиент-приложения, которое общается со службой REST, обеспеченной базовой аутентификацией HTTP.

2. Весенняя конфигурация безопасности

Прежде всего, давайте набудем API REST с Spring Security и Basic Auth:

Вот как она настроена:

@Configuration
@EnableWebSecurity
public class BasicAuthConfiguration 
  extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth)
      throws Exception {
        auth
          .inMemoryAuthentication()
          .withUser("user")
          .password("password")
          .roles("USER");
    }

    @Override
    protected void configure(HttpSecurity http) 
      throws Exception {
        http.csrf().disable()
          .authorizeRequests()
          .antMatchers("/login").permitAll()
          .anyRequest()
          .authenticated()
          .and()
          .httpBasic();
    }
}

Теперь давайте создадим конечные точки. Наш сервис REST будет иметь два – один для входа, а другой для получения пользовательских данных:

@RestController
@CrossOrigin
public class UserController {

    @RequestMapping("/login")
    public boolean login(@RequestBody User user) {
        return
          user.getUserName().equals("user") && user.getPassword().equals("password");
    }
	
    @RequestMapping("/user")
    public Principal user(HttpServletRequest request) {
        String authToken = request.getHeader("Authorization")
          .substring("Basic".length()).trim();
        return () ->  new String(Base64.getDecoder()
          .decode(authToken)).split(":")[0];
    }
}

Кроме того, вы можете проверить наш другой учебник о весенней безопасности OAuth2, а если вы заинтересованы в реализации сервера OAuth2 для авторизации.

3. Настройка углового клиента

Теперь, когда мы создали службу REST, давайте навеем страницу входа с различными версиями Angular клиента.

Примеры, которые мы увидим здесь, используют npm для управления зависимостью и nodejs для запуска приложения.

Angular использует архитектуру одной страницы, где все детские компоненты (в нашем случае это логин и домашние компоненты) вводятся в общий родительский DOM.

В отличие от AngularJS, которая использует JavaScript, угловая версия 2 далее использует TypeScript в качестве основного языка. Поэтому приложение также требует определенных вспомогательных файлов, которые необходимы для его правильной работы.

Из-за постепенных усовершенствований Angular необходимые файлы отличаются от версии к версии.

Давайте ознакомимся с каждым из них:

  • systemjs.config.js – конфигурации систем (версия 2)
  • package.json – Зависимости модуля узла (версия 2 года)
  • tsconfig.json – конфигурации typescript корневого уровня (версия 2 года)
  • tsconfig.app.json – Конфигурации Typescript уровня приложения (версия 4 года)
  • .angular- Кли .json – Угловые конфигурации CLI (версия 4 и 5)
  • angular.json – Угловые конфигурации CLI (версия 6 года)

4. Страница входа

4.1. Использование угловых

Давайте создадим индекс.html файл и добавить соответствующие зависимости к нему:



    

Так как это одностраничное приложение, все компоненты ребенка будут добавлены в элемент div с ng-вид атрибут, основанный на логике маршрутизации.

Теперь давайте создадим приложение.js который определяет URL-адрес для отображения компонентов:

(function () {
    'use strict';

    angular
        .module('app', ['ngRoute'])
        .config(config)
        .run(run);

    config.$inject = ['$routeProvider', '$locationProvider'];
    function config($routeProvider, $locationProvider) {
        $routeProvider.when('/', {
            controller: 'HomeController',
            templateUrl: 'home/home.view.html',
            controllerAs: 'vm'
        }).when('/login', {
            controller: 'LoginController',
            templateUrl: 'login/login.view.html',
            controllerAs: 'vm'
        }).otherwise({ redirectTo: '/login' });
    }

    run.$inject = ['$rootScope', '$location', '$http', '$window'];
    function run($rootScope, $location, $http, $window) {
        var userData = $window.sessionStorage.getItem('userData');
        if (userData) {
            $http.defaults.headers.common['Authorization']
              = 'Basic ' + JSON.parse(userData).authData;
        }

        $rootScope
        .$on('$locationChangeStart', function (event, next, current) {
            var restrictedPage
              = $.inArray($location.path(), ['/login']) === -1;
            var loggedIn
              = $window.sessionStorage.getItem('userData');
            if (restrictedPage && !loggedIn) {
                $location.path('/login');
            }
        });
    }
})();

Компонент входа состоит из двух файлов, login.controller.js , и login.view.html.

Давайте посмотрим на первый:

Login

Username is required
Password is required

и второй:

(function () {
    'use strict';
    angular
        .module('app')
        .controller('LoginController', LoginController);

    LoginController.$inject = ['$location', '$window', '$http'];
    function LoginController($location, $window, $http) {
        var vm = this;
        vm.login = login;

        (function initController() {
            $window.localStorage.setItem('token', '');
        })();

        function login() {
            $http({
                url: 'http://localhost:8082/login',
                method: "POST",
                data: { 
                    'userName': vm.username,
                    'password': vm.password
                }
            }).then(function (response) {
                if (response.data) {
                    var token
                      = $window.btoa(vm.username + ':' + vm.password);
                    var userData = {
                        userName: vm.username,
                        authData: token
                    }
                    $window.sessionStorage.setItem(
                      'userData', JSON.stringify(userData)
                    );
                    $http.defaults.headers.common['Authorization']
                      = 'Basic ' + token;
                    $location.path('/');
                } else {
                    alert("Authentication failed.")
                }
            });
        };
    }
})();

Контроллер будет вызывать службу REST, передавая имя пользователя и пароль. После успешной проверки подлинности он кодирует имя пользователя и пароль и хранит закодированный маркер в хранилище сеансов для использования в будущем.

Как и компонент входа, домашний компонент также состоит из двух файлов, home.view.html :

Hi {{vm.user}}!

You're logged in!!

Logout

и home.controller.js:

(function () {
    'use strict';
    angular
        .module('app')
        .controller('HomeController', HomeController);

    HomeController.$inject = ['$window', '$http', '$scope'];
    function HomeController($window, $http, $scope) {
        var vm = this;
        vm.user = null;

        initController();

        function initController() {
            $http({
                url: 'http://localhost:8082/user',
                method: "GET"
            }).then(function (response) {
                vm.user = response.data.name;
            }, function (error) {
                console.log(error);
            });
        };

        $scope.logout = function () {
            $window.sessionStorage.setItem('userData', '');
            $http.defaults.headers.common['Authorization'] = 'Basic';
        }
    }
})();

Домашний контроллер запрашивает данные пользователя, передавая Авторизация заголовок. Наша служба REST вернет данные пользователей только в том случае, если токен действителен.

Теперь давайте установим http-сервер для запуска приложения Angular:

npm install http-server --save

После установки мы можем открыть корневую папку проекта в командной подсказке и выполнить команду:

http-server -o

4.2. Использование угловой версии 2, 4, 5

индекс.html в версии 2 немного отличается от версии AngularJS:





    
    
    
    

    
    


    Loading...

main.ts является основной точкой входа приложения. Он загружает модуль приложения и, как следствие, браузер загружает страницу входа:

platformBrowserDynamic().bootstrapModule(AppModule);

app.routing.ts отвечает за маршрутизацию приложения:

const appRoutes: Routes = [
    { path: '', component: HomeComponent },
    { path: 'login', component: LoginComponent },
    { path: '**', redirectTo: '' }
];

export const routing = RouterModule.forRoot(appRoutes);

app.module.ts декларирует компоненты и импортирует соответствующие модули:

@NgModule({
    imports: [
        BrowserModule,
        FormsModule,
        HttpModule,
        routing
    ],
    declarations: [
        AppComponent,
        HomeComponent,
        LoginComponent
    ],
    bootstrap: [AppComponent]
})

export class AppModule { }

Поскольку мы создаем одностраничное приложение, давайте создадим корневой компонент, который добавляет к нему все компоненты:

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html'
})

export class AppComponent { }

app.component.html будет иметь только тег. Angular использует этот тег для механизма маршрутизации местоположения.

Теперь давайте создадим компонент входа и соответствующий шаблон в login.component.ts:

@Component({
    selector: 'login',
    templateUrl: './app/login/login.component.html'
})

export class LoginComponent implements OnInit {
    model: any = {};

    constructor(
        private route: ActivatedRoute,
        private router: Router,
        private http: Http
    ) { }

    ngOnInit() {
        sessionStorage.setItem('token', '');
    }

    login() {
        let url = 'http://localhost:8082/login';
        let result = this.http.post(url, {
            userName: this.model.username,
            password: this.model.password
        }).map(res => res.json()).subscribe(isValid => {
            if (isValid) {
                sessionStorage.setItem(
                  'token',
                  btoa(this.model.username + ':' + this.model.password)
                );
                this.router.navigate(['']);
            } else {
                alert("Authentication failed.");
            }
        });
    }
}

Наконец, давайте посмотрим на login.component.html :

Username is required
Password is required

4.3. Использование углового 6

Угловая команда внесли некоторые улучшения в версию 6. Из-за этих изменений, наш пример также будет немного отличаться по сравнению с другими версиями. Единственное изменение, в каком мы в нашем примере в отношении версии 6, находится в части вызова службы.

Вместо HttpModule , версия 6 импорт HttpClientModule из @angular/общий/http.

Часть вызова службы также будет немного отличаться от старых версий:

this.http.post>(url, {
    userName: this.model.username,
    password: this.model.password
}).subscribe(isValid => {
    if (isValid) {
        sessionStorage.setItem(
          'token', 
          btoa(this.model.username + ':' + this.model.password)
        );
	this.router.navigate(['']);
    } else {
        alert("Authentication failed.")
    }
});

5. Заключение

Мы узнали, как реализовать страницу входа в систему Spring Security с помощью Angular. С версии 4 мы можем использовать проект Angular CLI для легкой разработки и тестирования.

Как всегда, все примеры, которые мы обсуждали здесь можно найти в течение Проект GitHub .