Halaman Log Masuk Keselamatan Spring dengan Sudut

1. Gambaran keseluruhan

Dalam tutorial ini, kami akan membuat halaman log masuk menggunakan Spring Security dengan:

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

Aplikasi contoh yang akan kita bincangkan di sini terdiri daripada aplikasi klien yang berkomunikasi dengan perkhidmatan REST, diamankan dengan pengesahan HTTP asas.

2. Konfigurasi Keselamatan Musim Semi

Pertama sekali, mari sediakan REST API dengan Spring Security dan Basic Auth:

Inilah cara ia dikonfigurasi:

@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 kita buat titik akhir. Perkhidmatan REST kami mempunyai dua - satu untuk log masuk dan satu lagi 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]; } }

Begitu juga, anda boleh melihat tutorial kami yang lain mengenai Spring Security OAuth2 juga sekiranya anda berminat untuk melaksanakan pelayan OAuth2 untuk mendapatkan kebenaran.

3. Menetapkan Pelanggan Sudut

Sekarang setelah kita membuat perkhidmatan REST, mari kita siapkan halaman log masuk dengan versi klien Angular yang berbeza.

Contoh yang akan kita lihat di sini menggunakan npm untuk pengurusan pergantungan dan nodejs untuk menjalankan aplikasi.

Angular menggunakan seni bina satu halaman di mana semua komponen anak (dalam kes ini ini adalah komponen log masuk dan rumah) disuntikkan ke DOM ibu bapa biasa.

Tidak seperti AngularJS, yang menggunakan JavaScript, Angular versi 2 dan seterusnya menggunakan TypeScript sebagai bahasa utamanya. Oleh itu aplikasi juga memerlukan fail sokongan tertentu yang diperlukan agar ia berfungsi dengan betul.

Oleh kerana peningkatan tambahan Angular, fail yang diperlukan berbeza dari versi ke versi.

Mari kita ketahui setiap perkara ini:

  • systemjs.config.js - konfigurasi sistem (versi 2)
  • package.json - kebergantungan modul nod (versi 2 dan seterusnya)
  • tsconfig.json - konfigurasi Naskhah peringkat akar (versi 2 dan seterusnya)
  • tsconfig.app.json - tahap aplikasi Konfigurasi typescript (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 Log Masuk

4.1. Menggunakan AngularJS

Mari buat fail index.html dan tambahkan kebergantungan yang berkaitan dengannya:

Oleh kerana ini adalah aplikasi satu halaman, semua komponen anak akan ditambahkan ke elemen div dengan atribut ng-view berdasarkan logik penghalaan.

Sekarang mari kita buat app.js yang menentukan 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 log masuk terdiri daripada dua fail, login.controller.js , dan login.view.html.

Mari 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.") } }); }; } })();

Pengawal akan memanggil perkhidmatan REST dengan memasukkan nama pengguna dan kata laluan. Setelah pengesahan berjaya, ia akan menyandikan nama pengguna dan kata laluan dan menyimpan token yang dikodkan dalam simpanan sesi untuk penggunaan masa depan.

Sama dengan komponen log masuk, komponen rumah juga terdiri daripada dua fail, 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'; } } })();

Pengawal rumah akan meminta data pengguna dengan melewati tajuk Pengesahan . Perkhidmatan REST kami akan mengembalikan data pengguna hanya jika tokennya sah.

Sekarang mari pasang pelayan http untuk menjalankan aplikasi Angular:

npm install http-server --save

Setelah ini dipasang, kita dapat membuka folder root projek di command prompt dan melaksanakan perintah:

http-server -o

4.2. Menggunakan Angular Versi 2, 4, 5

The index.html dalam versi 2 berbeza sedikit daripada versi AngularJS yang:

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

The main.ts adalah pintu masuk utama permohonan. Ia memuat modul aplikasi dan hasilnya, penyemak imbas memuat halaman masuk:

platformBrowserDynamic().bootstrapModule(AppModule);

The app.routing.ts bertanggungjawab untuk penghalaan permohonan:

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.

Daripada HttpModule , versi 6 mengimport HttpClientModule dari @ angular / common / http.

Bahagian panggilan perkhidmatan juga akan sedikit berbeza dari versi 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 belajar bagaimana melaksanakan halaman log masuk Spring Security dengan Angular. Dari versi 4 dan seterusnya, kita dapat memanfaatkan projek Angular CLI untuk pembangunan dan pengujian yang mudah.

Seperti biasa semua contoh yang telah kita bincangkan di sini boleh didapati melalui projek GitHub.