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
и второй:
(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!!
и 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 будет иметь только
Теперь давайте создадим компонент входа и соответствующий шаблон в 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 :
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 .