Halaman Login Keamanan Musim Semi dengan Sudut

1. Ikhtisar

Dalam tutorial ini, kita akan membuat halaman login menggunakan Spring Security dengan:

  • AngularJS
  • Sudut 2, 4, 5, dan 6

Contoh aplikasi yang akan kita bahas di sini terdiri dari aplikasi klien yang berkomunikasi dengan layanan REST, diamankan dengan otentikasi HTTP dasar.

2. Konfigurasi Keamanan Pegas

Pertama-tama, mari kita siapkan REST API dengan Spring Security dan Basic Auth:

Berikut adalah cara konfigurasinya:

@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(); } }

Sekarang mari buat titik akhir. Layanan REST kami akan memiliki dua - satu untuk login dan yang lainnya untuk mengambil data pengguna:

@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]; } }

Selain itu, Anda juga dapat melihat tutorial kami yang lain tentang Spring Security OAuth2 jika Anda tertarik untuk menerapkan server OAuth2 untuk otorisasi.

3. Menyiapkan Klien Angular

Sekarang kita telah membuat layanan REST, mari kita siapkan halaman login dengan berbagai versi klien Angular.

Contoh yang akan kita lihat di sini menggunakan npm untuk manajemen ketergantungan dan nodejs untuk menjalankan aplikasi.

Angular menggunakan arsitektur halaman tunggal di mana semua komponen anak (dalam kasus kami ini adalah komponen login dan home) dimasukkan ke dalam DOM induk umum.

Tidak seperti AngularJS, yang menggunakan JavaScript, Angular versi 2 dan seterusnya menggunakan TypeScript sebagai bahasa utamanya. Karenanya aplikasi juga membutuhkan file pendukung tertentu yang diperlukan agar dapat berfungsi dengan benar.

Karena peningkatan bertahap Angular, file yang dibutuhkan berbeda dari versi ke versi.

Mari kenali masing-masing dari ini:

  • systemjs.config.js - konfigurasi sistem (versi 2)
  • package.json - dependensi modul node (versi 2 dan seterusnya)
  • tsconfig.json - konfigurasi Ketikan tingkat root (versi 2 dan seterusnya)
  • tsconfig.app.json - konfigurasi Script Type tingkat aplikasi (versi 4 dan seterusnya)
  • .angular- cli .json - Konfigurasi CLI sudut (versi 4 dan 5)
  • angular.json - Konfigurasi CLI sudut (versi 6 dan seterusnya)

4. Halaman Login

4.1. Menggunakan AngularJS

Mari buat file index.html dan tambahkan dependensi yang relevan dengannya:

Karena ini adalah aplikasi halaman tunggal, semua komponen turunan akan ditambahkan ke elemen div dengan atribut ng-view berdasarkan logika perutean.

Sekarang mari kita buat app.js yang mendefinisikan URL ke pemetaan komponen:

(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'); } }); } })();

Komponen login terdiri dari dua file, login.controller.js , dan login.view.html.

Mari kita lihat yang pertama:

Login

Username Username is required Password Password is required Login

dan yang kedua:

(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: '//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.") } }); }; } })();

Kontroler akan memanggil layanan REST dengan memasukkan nama pengguna dan kata sandi. Setelah otentikasi berhasil, itu akan menyandikan nama pengguna dan kata sandi dan menyimpan token yang disandikan dalam penyimpanan sesi untuk penggunaan di masa mendatang.

Mirip dengan komponen login, komponen home juga terdiri dari dua file, home.view.html :

You're logged in!!

Logout

dan 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: '//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'; } } })();

Pengontrol rumah akan meminta data pengguna dengan meneruskan header Otorisasi . Layanan REST kami akan mengembalikan data pengguna hanya jika token itu valid.

Sekarang mari instal http-server untuk menjalankan aplikasi Angular:

npm install http-server --save

Setelah ini diinstal, kita dapat membuka folder root proyek di command prompt dan menjalankan perintah:

http-server -o

4.2. Menggunakan Angular Versi 2, 4, 5

The index.html dalam versi 2 berbeda sedikit dari versi AngularJS:

         System.import('app').catch(function (err) { console.error(err); });    Loading...  

The main.ts adalah titik masuk utama aplikasi. Ini mem-bootstrap modul aplikasi dan sebagai hasilnya, browser memuat halaman login:

platformBrowserDynamic().bootstrapModule(AppModule);

The app.routing.ts bertanggung jawab untuk routing aplikasi:

const appRoutes: Routes = [ { path: '', component: HomeComponent }, { path: 'login', component: LoginComponent }, { path: '**', redirectTo: '' } ]; export const routing = RouterModule.forRoot(appRoutes);

The app.module.ts declares the components and imports the relevant modules:

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

Since we're creating a single page application, let's create a root component which adds all the child components to it:

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

The app.component.html will have only a tag. The Angular uses this tag for its location routing mechanism.

Now let's create the login component and its corresponding template in 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 = '//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."); } }); } }

Finally, let's have a look at the login.component.html:

 Username Username is required Password Password is required Login 

4.3. Using Angular 6

Angular team has made some enhancements in version 6. Due to these changes, our example will also be a little different compared to other versions. The only change we've in our example with respect to version 6 is in the service calling part.

Alih-alih HttpModule , versi 6 mengimpor HttpClientModule dari @ angular / common / http.

Bagian panggilan layanan juga akan sedikit berbeda dari versi yang lebih lama:

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. Kesimpulan

Kami telah mempelajari cara menerapkan halaman login Keamanan Musim Semi dengan Angular. Mulai versi 4 dan seterusnya, kita dapat menggunakan proyek CLI Angular untuk pengembangan dan pengujian yang mudah.

Seperti biasa, semua contoh yang telah kita diskusikan di sini dapat ditemukan melalui proyek GitHub.