├── .angulardoc.json ├── .gitignore ├── LICENSE ├── README.md ├── bin ├── main │ ├── application.properties │ └── com │ │ └── djamware │ │ └── springangularauth │ │ ├── ServletInitializer.class │ │ ├── SpringAngularAuthApplication.class │ │ ├── configs │ │ ├── JwtConfigurer.class │ │ ├── JwtTokenFilter.class │ │ ├── JwtTokenProvider.class │ │ └── WebSecurityConfig.class │ │ ├── controllers │ │ ├── AuthBody.class │ │ ├── AuthController.class │ │ └── ProductController.class │ │ ├── models │ │ ├── Products.class │ │ ├── Role.class │ │ └── User.class │ │ ├── repositories │ │ ├── ProductRepository.class │ │ ├── RoleRepository.class │ │ └── UserRepository.class │ │ └── services │ │ └── CustomUserDetailsService.class └── test │ └── com │ └── djamware │ └── springangularauth │ └── SpringAngularAuthApplicationTests.class ├── build.gradle ├── client ├── .editorconfig ├── .gitignore ├── angular.json ├── browserslist ├── e2e │ ├── protractor.conf.js │ ├── src │ │ ├── app.e2e-spec.ts │ │ └── app.po.ts │ └── tsconfig.json ├── karma.conf.js ├── package-lock.json ├── package.json ├── src │ ├── app │ │ ├── app-routing.module.ts │ │ ├── app.component.html │ │ ├── app.component.scss │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── auth.service.spec.ts │ │ ├── auth.service.ts │ │ ├── auth │ │ │ ├── auth.guard.spec.ts │ │ │ ├── auth.guard.ts │ │ │ ├── login │ │ │ │ ├── login.component.html │ │ │ │ ├── login.component.scss │ │ │ │ ├── login.component.spec.ts │ │ │ │ └── login.component.ts │ │ │ └── register │ │ │ │ ├── register.component.html │ │ │ │ ├── register.component.scss │ │ │ │ ├── register.component.spec.ts │ │ │ │ └── register.component.ts │ │ ├── interceptors │ │ │ └── token.interceptor.ts │ │ ├── product.service.spec.ts │ │ ├── product.service.ts │ │ └── products │ │ │ ├── product.ts │ │ │ ├── products.component.html │ │ │ ├── products.component.scss │ │ │ ├── products.component.spec.ts │ │ │ └── products.component.ts │ ├── assets │ │ └── .gitkeep │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.scss │ └── test.ts ├── tsconfig.app.json ├── tsconfig.json ├── tsconfig.spec.json └── tslint.json ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src ├── main ├── java │ └── com │ │ └── djamware │ │ └── springangularauth │ │ ├── ServletInitializer.java │ │ ├── SpringAngularAuthApplication.java │ │ ├── configs │ │ ├── JwtConfigurer.java │ │ ├── JwtTokenFilter.java │ │ ├── JwtTokenProvider.java │ │ └── WebSecurityConfig.java │ │ ├── controllers │ │ ├── AuthBody.java │ │ ├── AuthController.java │ │ └── ProductController.java │ │ ├── models │ │ ├── Products.java │ │ ├── Role.java │ │ └── User.java │ │ ├── repositories │ │ ├── ProductRepository.java │ │ ├── RoleRepository.java │ │ └── UserRepository.java │ │ └── services │ │ └── CustomUserDetailsService.java └── resources │ └── application.properties └── test └── java └── com └── djamware └── springangularauth └── SpringAngularAuthApplicationTests.java /.angulardoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "repoId": "77668690-ca90-42b3-98ba-8218d25d54b3", 3 | "lastSync": 0 4 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/** 6 | !**/src/test/** 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | 17 | ### IntelliJ IDEA ### 18 | .idea 19 | *.iws 20 | *.iml 21 | *.ipr 22 | out/ 23 | 24 | ### NetBeans ### 25 | /nbproject/private/ 26 | /nbbuild/ 27 | /dist/ 28 | /nbdist/ 29 | /.nb-gradle/ 30 | 31 | ### VS Code ### 32 | .vscode/ 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Didin Jamaludin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spring Boot, Security, MongoDB, Angular 8: Build Authentication 2 | 3 | This source code is part of [Spring Boot, Security, MongoDB, Angular 8: Build Authentication](https://www.djamware.com/post/5d3332980707cc65eac46c7b/spring-boot-security-mongodb-angular-8-build-authentication) tutorial 4 | -------------------------------------------------------------------------------- /bin/main/application.properties: -------------------------------------------------------------------------------- 1 | spring.data.mongodb.database=springmongodb 2 | spring.data.mongodb.host=localhost 3 | spring.data.mongodb.port=27017 4 | -------------------------------------------------------------------------------- /bin/main/com/djamware/springangularauth/ServletInitializer.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didinj/spring-boot-mongodb-security-angular8/bfcaa8b4f82e6eb8302acb69466af1376a13c43b/bin/main/com/djamware/springangularauth/ServletInitializer.class -------------------------------------------------------------------------------- /bin/main/com/djamware/springangularauth/SpringAngularAuthApplication.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didinj/spring-boot-mongodb-security-angular8/bfcaa8b4f82e6eb8302acb69466af1376a13c43b/bin/main/com/djamware/springangularauth/SpringAngularAuthApplication.class -------------------------------------------------------------------------------- /bin/main/com/djamware/springangularauth/configs/JwtConfigurer.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didinj/spring-boot-mongodb-security-angular8/bfcaa8b4f82e6eb8302acb69466af1376a13c43b/bin/main/com/djamware/springangularauth/configs/JwtConfigurer.class -------------------------------------------------------------------------------- /bin/main/com/djamware/springangularauth/configs/JwtTokenFilter.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didinj/spring-boot-mongodb-security-angular8/bfcaa8b4f82e6eb8302acb69466af1376a13c43b/bin/main/com/djamware/springangularauth/configs/JwtTokenFilter.class -------------------------------------------------------------------------------- /bin/main/com/djamware/springangularauth/configs/JwtTokenProvider.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didinj/spring-boot-mongodb-security-angular8/bfcaa8b4f82e6eb8302acb69466af1376a13c43b/bin/main/com/djamware/springangularauth/configs/JwtTokenProvider.class -------------------------------------------------------------------------------- /bin/main/com/djamware/springangularauth/configs/WebSecurityConfig.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didinj/spring-boot-mongodb-security-angular8/bfcaa8b4f82e6eb8302acb69466af1376a13c43b/bin/main/com/djamware/springangularauth/configs/WebSecurityConfig.class -------------------------------------------------------------------------------- /bin/main/com/djamware/springangularauth/controllers/AuthBody.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didinj/spring-boot-mongodb-security-angular8/bfcaa8b4f82e6eb8302acb69466af1376a13c43b/bin/main/com/djamware/springangularauth/controllers/AuthBody.class -------------------------------------------------------------------------------- /bin/main/com/djamware/springangularauth/controllers/AuthController.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didinj/spring-boot-mongodb-security-angular8/bfcaa8b4f82e6eb8302acb69466af1376a13c43b/bin/main/com/djamware/springangularauth/controllers/AuthController.class -------------------------------------------------------------------------------- /bin/main/com/djamware/springangularauth/controllers/ProductController.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didinj/spring-boot-mongodb-security-angular8/bfcaa8b4f82e6eb8302acb69466af1376a13c43b/bin/main/com/djamware/springangularauth/controllers/ProductController.class -------------------------------------------------------------------------------- /bin/main/com/djamware/springangularauth/models/Products.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didinj/spring-boot-mongodb-security-angular8/bfcaa8b4f82e6eb8302acb69466af1376a13c43b/bin/main/com/djamware/springangularauth/models/Products.class -------------------------------------------------------------------------------- /bin/main/com/djamware/springangularauth/models/Role.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didinj/spring-boot-mongodb-security-angular8/bfcaa8b4f82e6eb8302acb69466af1376a13c43b/bin/main/com/djamware/springangularauth/models/Role.class -------------------------------------------------------------------------------- /bin/main/com/djamware/springangularauth/models/User.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didinj/spring-boot-mongodb-security-angular8/bfcaa8b4f82e6eb8302acb69466af1376a13c43b/bin/main/com/djamware/springangularauth/models/User.class -------------------------------------------------------------------------------- /bin/main/com/djamware/springangularauth/repositories/ProductRepository.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didinj/spring-boot-mongodb-security-angular8/bfcaa8b4f82e6eb8302acb69466af1376a13c43b/bin/main/com/djamware/springangularauth/repositories/ProductRepository.class -------------------------------------------------------------------------------- /bin/main/com/djamware/springangularauth/repositories/RoleRepository.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didinj/spring-boot-mongodb-security-angular8/bfcaa8b4f82e6eb8302acb69466af1376a13c43b/bin/main/com/djamware/springangularauth/repositories/RoleRepository.class -------------------------------------------------------------------------------- /bin/main/com/djamware/springangularauth/repositories/UserRepository.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didinj/spring-boot-mongodb-security-angular8/bfcaa8b4f82e6eb8302acb69466af1376a13c43b/bin/main/com/djamware/springangularauth/repositories/UserRepository.class -------------------------------------------------------------------------------- /bin/main/com/djamware/springangularauth/services/CustomUserDetailsService.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didinj/spring-boot-mongodb-security-angular8/bfcaa8b4f82e6eb8302acb69466af1376a13c43b/bin/main/com/djamware/springangularauth/services/CustomUserDetailsService.class -------------------------------------------------------------------------------- /bin/test/com/djamware/springangularauth/SpringAngularAuthApplicationTests.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didinj/spring-boot-mongodb-security-angular8/bfcaa8b4f82e6eb8302acb69466af1376a13c43b/bin/test/com/djamware/springangularauth/SpringAngularAuthApplicationTests.class -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.springframework.boot' version '2.1.6.RELEASE' 3 | id 'java' 4 | id 'war' 5 | } 6 | 7 | apply plugin: 'io.spring.dependency-management' 8 | 9 | group = 'com.djamware' 10 | version = '0.0.1-SNAPSHOT' 11 | sourceCompatibility = '1.8' 12 | 13 | repositories { 14 | mavenCentral() 15 | } 16 | 17 | dependencies { 18 | implementation 'org.springframework.boot:spring-boot-starter-data-mongodb-reactive' 19 | implementation 'org.springframework.boot:spring-boot-starter-security' 20 | implementation 'org.springframework.boot:spring-boot-starter-web' 21 | implementation 'javax.xml.bind:jaxb-api:2.1' 22 | implementation 'io.jsonwebtoken:jjwt:0.9.1' 23 | providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' 24 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 25 | testImplementation 'org.springframework.security:spring-security-test' 26 | } 27 | -------------------------------------------------------------------------------- /client/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /client/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events.json 15 | speed-measure-plugin.json 16 | 17 | # IDEs and editors 18 | /.idea 19 | .project 20 | .classpath 21 | .c9/ 22 | *.launch 23 | .settings/ 24 | *.sublime-workspace 25 | 26 | # IDE - VSCode 27 | .vscode/* 28 | !.vscode/settings.json 29 | !.vscode/tasks.json 30 | !.vscode/launch.json 31 | !.vscode/extensions.json 32 | .history/* 33 | 34 | # misc 35 | /.sass-cache 36 | /connect.lock 37 | /coverage 38 | /libpeerconnection.log 39 | npm-debug.log 40 | yarn-error.log 41 | testem.log 42 | /typings 43 | 44 | # System Files 45 | .DS_Store 46 | Thumbs.db 47 | -------------------------------------------------------------------------------- /client/angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "client": { 7 | "projectType": "application", 8 | "schematics": { 9 | "@schematics/angular:component": { 10 | "style": "scss" 11 | } 12 | }, 13 | "root": "", 14 | "sourceRoot": "src", 15 | "prefix": "app", 16 | "architect": { 17 | "build": { 18 | "builder": "@angular-devkit/build-angular:browser", 19 | "options": { 20 | "outputPath": "dist/client", 21 | "index": "src/index.html", 22 | "main": "src/main.ts", 23 | "polyfills": "src/polyfills.ts", 24 | "tsConfig": "tsconfig.app.json", 25 | "aot": false, 26 | "assets": [ 27 | "src/favicon.ico", 28 | "src/assets" 29 | ], 30 | "styles": [ 31 | "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", 32 | "src/styles.scss" 33 | ], 34 | "scripts": [] 35 | }, 36 | "configurations": { 37 | "production": { 38 | "fileReplacements": [ 39 | { 40 | "replace": "src/environments/environment.ts", 41 | "with": "src/environments/environment.prod.ts" 42 | } 43 | ], 44 | "optimization": true, 45 | "outputHashing": "all", 46 | "sourceMap": false, 47 | "extractCss": true, 48 | "namedChunks": false, 49 | "aot": true, 50 | "extractLicenses": true, 51 | "vendorChunk": false, 52 | "buildOptimizer": true, 53 | "budgets": [ 54 | { 55 | "type": "initial", 56 | "maximumWarning": "2mb", 57 | "maximumError": "5mb" 58 | } 59 | ] 60 | } 61 | } 62 | }, 63 | "serve": { 64 | "builder": "@angular-devkit/build-angular:dev-server", 65 | "options": { 66 | "browserTarget": "client:build" 67 | }, 68 | "configurations": { 69 | "production": { 70 | "browserTarget": "client:build:production" 71 | } 72 | } 73 | }, 74 | "extract-i18n": { 75 | "builder": "@angular-devkit/build-angular:extract-i18n", 76 | "options": { 77 | "browserTarget": "client:build" 78 | } 79 | }, 80 | "test": { 81 | "builder": "@angular-devkit/build-angular:karma", 82 | "options": { 83 | "main": "src/test.ts", 84 | "polyfills": "src/polyfills.ts", 85 | "tsConfig": "tsconfig.spec.json", 86 | "karmaConfig": "karma.conf.js", 87 | "assets": [ 88 | "src/favicon.ico", 89 | "src/assets" 90 | ], 91 | "styles": [ 92 | "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", 93 | "src/styles.scss" 94 | ], 95 | "scripts": [] 96 | } 97 | }, 98 | "lint": { 99 | "builder": "@angular-devkit/build-angular:tslint", 100 | "options": { 101 | "tsConfig": [ 102 | "tsconfig.app.json", 103 | "tsconfig.spec.json", 104 | "e2e/tsconfig.json" 105 | ], 106 | "exclude": [ 107 | "**/node_modules/**" 108 | ] 109 | } 110 | }, 111 | "e2e": { 112 | "builder": "@angular-devkit/build-angular:protractor", 113 | "options": { 114 | "protractorConfig": "e2e/protractor.conf.js", 115 | "devServerTarget": "client:serve" 116 | }, 117 | "configurations": { 118 | "production": { 119 | "devServerTarget": "client:serve:production" 120 | } 121 | } 122 | } 123 | } 124 | } 125 | }, 126 | "defaultProject": "client" 127 | } -------------------------------------------------------------------------------- /client/browserslist: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /client/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Protractor configuration file, see link for more information 3 | // https://github.com/angular/protractor/blob/master/lib/config.ts 4 | 5 | const { SpecReporter } = require('jasmine-spec-reporter'); 6 | 7 | /** 8 | * @type { import("protractor").Config } 9 | */ 10 | exports.config = { 11 | allScriptsTimeout: 11000, 12 | specs: [ 13 | './src/**/*.e2e-spec.ts' 14 | ], 15 | capabilities: { 16 | 'browserName': 'chrome' 17 | }, 18 | directConnect: true, 19 | baseUrl: 'http://localhost:4200/', 20 | framework: 'jasmine', 21 | jasmineNodeOpts: { 22 | showColors: true, 23 | defaultTimeoutInterval: 30000, 24 | print: function() {} 25 | }, 26 | onPrepare() { 27 | require('ts-node').register({ 28 | project: require('path').join(__dirname, './tsconfig.json') 29 | }); 30 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 31 | } 32 | }; -------------------------------------------------------------------------------- /client/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('Welcome to client!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /client/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText() { 9 | return element(by.css('app-root h1')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /client/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /client/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, './coverage/client'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e" 11 | }, 12 | "private": true, 13 | "dependencies": { 14 | "@angular/animations": "~8.1.2", 15 | "@angular/cdk": "~8.1.1", 16 | "@angular/common": "~8.1.2", 17 | "@angular/compiler": "~8.1.2", 18 | "@angular/core": "~8.1.2", 19 | "@angular/forms": "~8.1.2", 20 | "@angular/material": "^8.1.1", 21 | "@angular/platform-browser": "~8.1.2", 22 | "@angular/platform-browser-dynamic": "~8.1.2", 23 | "@angular/router": "~8.1.2", 24 | "hammerjs": "^2.0.8", 25 | "rxjs": "~6.4.0", 26 | "tslib": "^1.9.0", 27 | "zone.js": "~0.9.1" 28 | }, 29 | "devDependencies": { 30 | "@angular-devkit/build-angular": "~0.801.2", 31 | "@angular/cli": "~8.1.2", 32 | "@angular/compiler-cli": "~8.1.2", 33 | "@angular/language-service": "~8.1.2", 34 | "@types/node": "~8.9.4", 35 | "@types/jasmine": "~3.3.8", 36 | "@types/jasminewd2": "~2.0.3", 37 | "codelyzer": "^5.0.0", 38 | "jasmine-core": "~3.4.0", 39 | "jasmine-spec-reporter": "~4.2.1", 40 | "karma": "~6.3.16", 41 | "karma-chrome-launcher": "~2.2.0", 42 | "karma-coverage-istanbul-reporter": "~2.0.1", 43 | "karma-jasmine": "~2.0.1", 44 | "karma-jasmine-html-reporter": "^1.4.0", 45 | "protractor": "~5.4.0", 46 | "ts-node": "~7.0.0", 47 | "tslint": "~5.15.0", 48 | "typescript": "~3.4.3" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /client/src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | import { ProductsComponent } from './products/products.component'; 4 | import { LoginComponent } from './auth/login/login.component'; 5 | import { RegisterComponent } from './auth/register/register.component'; 6 | import { AuthGuard } from './auth/auth.guard'; 7 | 8 | const routes: Routes = [ 9 | { 10 | path: '', 11 | redirectTo: 'products', 12 | pathMatch: 'full' 13 | }, 14 | { 15 | path: 'products', 16 | canActivate: [AuthGuard], 17 | component: ProductsComponent, 18 | data: { title: 'List of Products' } 19 | }, 20 | { 21 | path: 'login', 22 | component: LoginComponent, 23 | data: { title: 'Login' } 24 | }, 25 | { 26 | path: 'register', 27 | component: RegisterComponent, 28 | data: { title: 'Register' } 29 | } 30 | ]; 31 | 32 | @NgModule({ 33 | imports: [RouterModule.forRoot(routes)], 34 | exports: [RouterModule] 35 | }) 36 | export class AppRoutingModule { } 37 | -------------------------------------------------------------------------------- /client/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /client/src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | .container { 2 | padding: 20px; 3 | } 4 | -------------------------------------------------------------------------------- /client/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { RouterTestingModule } from '@angular/router/testing'; 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async(() => { 7 | TestBed.configureTestingModule({ 8 | imports: [ 9 | RouterTestingModule 10 | ], 11 | declarations: [ 12 | AppComponent 13 | ], 14 | }).compileComponents(); 15 | })); 16 | 17 | it('should create the app', () => { 18 | const fixture = TestBed.createComponent(AppComponent); 19 | const app = fixture.debugElement.componentInstance; 20 | expect(app).toBeTruthy(); 21 | }); 22 | 23 | it(`should have as title 'client'`, () => { 24 | const fixture = TestBed.createComponent(AppComponent); 25 | const app = fixture.debugElement.componentInstance; 26 | expect(app.title).toEqual('client'); 27 | }); 28 | 29 | it('should render title in a h1 tag', () => { 30 | const fixture = TestBed.createComponent(AppComponent); 31 | fixture.detectChanges(); 32 | const compiled = fixture.debugElement.nativeElement; 33 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to client!'); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /client/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.scss'] 7 | }) 8 | export class AppComponent { 9 | title = 'client'; 10 | } 11 | -------------------------------------------------------------------------------- /client/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | 4 | import { AppRoutingModule } from './app-routing.module'; 5 | import { AppComponent } from './app.component'; 6 | import { ProductsComponent } from './products/products.component'; 7 | import { LoginComponent } from './auth/login/login.component'; 8 | import { RegisterComponent } from './auth/register/register.component'; 9 | 10 | import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http'; 11 | import { TokenInterceptor } from './interceptors/token.interceptor'; 12 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 13 | 14 | import { 15 | MatInputModule, 16 | MatPaginatorModule, 17 | MatProgressSpinnerModule, 18 | MatSortModule, 19 | MatTableModule, 20 | MatIconModule, 21 | MatButtonModule, 22 | MatCardModule, 23 | MatFormFieldModule } from '@angular/material'; 24 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 25 | 26 | @NgModule({ 27 | declarations: [ 28 | AppComponent, 29 | ProductsComponent, 30 | LoginComponent, 31 | RegisterComponent 32 | ], 33 | imports: [ 34 | BrowserModule, 35 | AppRoutingModule, 36 | HttpClientModule, 37 | ReactiveFormsModule, 38 | BrowserAnimationsModule, 39 | MatInputModule, 40 | MatTableModule, 41 | MatPaginatorModule, 42 | MatSortModule, 43 | MatProgressSpinnerModule, 44 | MatIconModule, 45 | MatButtonModule, 46 | MatCardModule, 47 | MatFormFieldModule 48 | ], 49 | providers: [ 50 | { 51 | provide: HTTP_INTERCEPTORS, 52 | useClass: TokenInterceptor, 53 | multi: true 54 | } 55 | ], 56 | bootstrap: [AppComponent] 57 | }) 58 | export class AppModule { } 59 | -------------------------------------------------------------------------------- /client/src/app/auth.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { AuthService } from './auth.service'; 4 | 5 | describe('AuthService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: AuthService = TestBed.get(AuthService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /client/src/app/auth.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | import { Observable, of } from 'rxjs'; 4 | import { catchError, tap } from 'rxjs/operators'; 5 | 6 | const apiUrl = 'http://192.168.0.7:8080/api/auth/'; 7 | 8 | @Injectable({ 9 | providedIn: 'root' 10 | }) 11 | export class AuthService { 12 | 13 | isLoggedIn = false; 14 | redirectUrl: string; 15 | 16 | constructor(private http: HttpClient) { } 17 | 18 | login(data: any): Observable { 19 | return this.http.post(apiUrl + 'login', data) 20 | .pipe( 21 | tap(_ => this.isLoggedIn = true), 22 | catchError(this.handleError('login', [])) 23 | ); 24 | } 25 | 26 | logout(): Observable { 27 | return this.http.get(apiUrl + 'signout') 28 | .pipe( 29 | tap(_ => this.isLoggedIn = false), 30 | catchError(this.handleError('logout', [])) 31 | ); 32 | } 33 | 34 | register(data: any): Observable { 35 | return this.http.post(apiUrl + 'register', data) 36 | .pipe( 37 | tap(_ => this.log('login')), 38 | catchError(this.handleError('login', [])) 39 | ); 40 | } 41 | 42 | private handleError(operation = 'operation', result?: T) { 43 | return (error: any): Observable => { 44 | 45 | console.error(error); // log to console instead 46 | this.log(`${operation} failed: ${error.message}`); 47 | 48 | return of(result as T); 49 | }; 50 | } 51 | 52 | private log(message: string) { 53 | console.log(message); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /client/src/app/auth/auth.guard.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async, inject } from '@angular/core/testing'; 2 | 3 | import { AuthGuard } from './auth.guard'; 4 | 5 | describe('AuthGuard', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [AuthGuard] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([AuthGuard], (guard: AuthGuard) => { 13 | expect(guard).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /client/src/app/auth/auth.guard.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router'; 3 | import { Observable } from 'rxjs'; 4 | import { AuthService } from '../auth.service'; 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class AuthGuard implements CanActivate { 10 | 11 | constructor(private authService: AuthService, private router: Router) {} 12 | 13 | canActivate( 14 | next: ActivatedRouteSnapshot, 15 | state: RouterStateSnapshot): boolean { 16 | const url: string = state.url; 17 | 18 | return this.checkLogin(url); 19 | } 20 | 21 | checkLogin(url: string): boolean { 22 | if (this.authService.isLoggedIn) { return true; } 23 | 24 | // Store the attempted URL for redirecting 25 | this.authService.redirectUrl = url; 26 | 27 | // Navigate to the login page with extras 28 | this.router.navigate(['/login']); 29 | return false; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /client/src/app/auth/login/login.component.html: -------------------------------------------------------------------------------- 1 |
2 |
4 | 5 |
6 | 7 |
8 | 9 | 11 | 12 | Please enter your email 13 | 14 | 15 | 16 | 18 | 19 | Please enter your password 20 | 21 | 22 |
23 | 24 |
25 |
26 | 27 |
28 |
29 |
30 |
31 | -------------------------------------------------------------------------------- /client/src/app/auth/login/login.component.scss: -------------------------------------------------------------------------------- 1 | /* Structure */ 2 | .example-container { 3 | position: relative; 4 | padding: 5px; 5 | } 6 | 7 | .example-form { 8 | min-width: 150px; 9 | max-width: 500px; 10 | width: 100%; 11 | } 12 | 13 | .example-full-width { 14 | width: 100%; 15 | } 16 | 17 | .example-full-width:nth-last-child(0) { 18 | margin-bottom: 10px; 19 | } 20 | 21 | .button-row { 22 | margin: 10px 0; 23 | } 24 | 25 | .mat-flat-button { 26 | margin: 5px; 27 | } 28 | -------------------------------------------------------------------------------- /client/src/app/auth/login/login.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LoginComponent } from './login.component'; 4 | 5 | describe('LoginComponent', () => { 6 | let component: LoginComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LoginComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LoginComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/auth/login/login.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { FormControl, FormGroupDirective, FormBuilder, FormGroup, NgForm, Validators } from '@angular/forms'; 3 | import { AuthService } from '../../auth.service'; 4 | import { Router } from '@angular/router'; 5 | import { ErrorStateMatcher } from '@angular/material/core'; 6 | 7 | /** Error when invalid control is dirty, touched, or submitted. */ 8 | export class MyErrorStateMatcher implements ErrorStateMatcher { 9 | isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { 10 | const isSubmitted = form && form.submitted; 11 | return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted)); 12 | } 13 | } 14 | 15 | @Component({ 16 | selector: 'app-login', 17 | templateUrl: './login.component.html', 18 | styleUrls: ['./login.component.scss'] 19 | }) 20 | export class LoginComponent implements OnInit { 21 | 22 | loginForm: FormGroup; 23 | email = ''; 24 | password = ''; 25 | matcher = new MyErrorStateMatcher(); 26 | isLoadingResults = false; 27 | 28 | constructor(private formBuilder: FormBuilder, private router: Router, private authService: AuthService) { } 29 | 30 | ngOnInit() { 31 | this.loginForm = this.formBuilder.group({ 32 | 'email' : [null, Validators.required], 33 | 'password' : [null, Validators.required] 34 | }); 35 | } 36 | 37 | onFormSubmit(form: NgForm) { 38 | this.authService.login(form) 39 | .subscribe(res => { 40 | if (res.token) { 41 | localStorage.setItem('token', res.token); 42 | this.router.navigate(['products']); 43 | } 44 | }, (err) => { 45 | console.log(err); 46 | }); 47 | } 48 | 49 | register() { 50 | this.router.navigate(['register']); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /client/src/app/auth/register/register.component.html: -------------------------------------------------------------------------------- 1 |
2 |
4 | 5 |
6 | 7 |
8 | 9 | 11 | 12 | Please enter your Full Name 13 | 14 | 15 | 16 | 18 | 19 | Please enter your email 20 | 21 | 22 | 23 | 25 | 26 | Please enter your password 27 | 28 | 29 |
30 | 31 |
32 |
33 |
34 |
35 | -------------------------------------------------------------------------------- /client/src/app/auth/register/register.component.scss: -------------------------------------------------------------------------------- 1 | /* Structure */ 2 | .example-container { 3 | position: relative; 4 | padding: 5px; 5 | } 6 | 7 | .example-form { 8 | min-width: 150px; 9 | max-width: 500px; 10 | width: 100%; 11 | } 12 | 13 | .example-full-width { 14 | width: 100%; 15 | } 16 | 17 | .example-full-width:nth-last-child(0) { 18 | margin-bottom: 10px; 19 | } 20 | 21 | .button-row { 22 | margin: 10px 0; 23 | } 24 | 25 | .mat-flat-button { 26 | margin: 5px; 27 | } 28 | -------------------------------------------------------------------------------- /client/src/app/auth/register/register.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RegisterComponent } from './register.component'; 4 | 5 | describe('RegisterComponent', () => { 6 | let component: RegisterComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RegisterComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RegisterComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/auth/register/register.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { FormControl, FormGroupDirective, FormBuilder, FormGroup, NgForm, Validators } from '@angular/forms'; 3 | import { AuthService } from '../../auth.service'; 4 | import { Router } from '@angular/router'; 5 | import { ErrorStateMatcher } from '@angular/material/core'; 6 | 7 | /** Error when invalid control is dirty, touched, or submitted. */ 8 | export class MyErrorStateMatcher implements ErrorStateMatcher { 9 | isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { 10 | const isSubmitted = form && form.submitted; 11 | return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted)); 12 | } 13 | } 14 | 15 | @Component({ 16 | selector: 'app-register', 17 | templateUrl: './register.component.html', 18 | styleUrls: ['./register.component.scss'] 19 | }) 20 | export class RegisterComponent implements OnInit { 21 | 22 | registerForm: FormGroup; 23 | fullName = ''; 24 | email = ''; 25 | password = ''; 26 | isLoadingResults = false; 27 | matcher = new MyErrorStateMatcher(); 28 | 29 | constructor(private formBuilder: FormBuilder, private router: Router, private authService: AuthService) { } 30 | 31 | ngOnInit() { 32 | this.registerForm = this.formBuilder.group({ 33 | 'fullName' : [null, Validators.required], 34 | 'email' : [null, Validators.required], 35 | 'password' : [null, Validators.required] 36 | }); 37 | } 38 | 39 | onFormSubmit(form: NgForm) { 40 | this.authService.register(form) 41 | .subscribe(res => { 42 | this.router.navigate(['login']); 43 | }, (err) => { 44 | console.log(err); 45 | alert(err.error); 46 | }); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /client/src/app/interceptors/token.interceptor.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { 3 | HttpRequest, 4 | HttpHandler, 5 | HttpEvent, 6 | HttpInterceptor, 7 | HttpResponse, 8 | HttpErrorResponse 9 | } from '@angular/common/http'; 10 | import { Observable, throwError } from 'rxjs'; 11 | import { map, catchError } from 'rxjs/operators'; 12 | import { Router } from '@angular/router'; 13 | 14 | @Injectable() 15 | export class TokenInterceptor implements HttpInterceptor { 16 | 17 | constructor(private router: Router) {} 18 | 19 | intercept(request: HttpRequest, next: HttpHandler): Observable> { 20 | 21 | const token = localStorage.getItem('token'); 22 | if (token) { 23 | request = request.clone({ 24 | setHeaders: { 25 | 'Authorization': 'Bearer ' + token 26 | } 27 | }); 28 | } 29 | if (!request.headers.has('Content-Type')) { 30 | request = request.clone({ 31 | setHeaders: { 32 | 'content-type': 'application/json' 33 | } 34 | }); 35 | } 36 | request = request.clone({ 37 | headers: request.headers.set('Accept', 'application/json') 38 | }); 39 | return next.handle(request).pipe( 40 | map((event: HttpEvent) => { 41 | if (event instanceof HttpResponse) { 42 | console.log('event--->>>', event); 43 | } 44 | return event; 45 | }), 46 | catchError((error: HttpErrorResponse) => { 47 | console.log(error); 48 | if (error.status === 401) { 49 | this.router.navigate(['login']); 50 | } 51 | if (error.status === 400) { 52 | alert(error.error); 53 | } 54 | return throwError(error); 55 | })); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /client/src/app/product.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { ProductService } from './product.service'; 4 | 5 | describe('ProductService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: ProductService = TestBed.get(ProductService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /client/src/app/product.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Product } from './products/product'; 3 | import { HttpClient } from '@angular/common/http'; 4 | import { Observable, of } from 'rxjs'; 5 | import { catchError, tap } from 'rxjs/operators'; 6 | 7 | const apiUrl = 'http://192.168.0.7:8080/api/products'; 8 | 9 | @Injectable({ 10 | providedIn: 'root' 11 | }) 12 | export class ProductService { 13 | 14 | constructor(private http: HttpClient) { } 15 | 16 | getProducts(): Observable { 17 | return this.http.get(apiUrl) 18 | .pipe( 19 | tap(_ => this.log('fetched Products')), 20 | catchError(this.handleError('getProducts', [])) 21 | ); 22 | } 23 | 24 | private handleError(operation = 'operation', result?: T) { 25 | return (error: any): Observable => { 26 | 27 | console.error(error); // log to console instead 28 | this.log(`${operation} failed: ${error.message}`); 29 | 30 | return of(result as T); 31 | }; 32 | } 33 | 34 | private log(message: string) { 35 | console.log(message); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /client/src/app/products/product.ts: -------------------------------------------------------------------------------- 1 | export class Product { 2 | productId: number; 3 | isbn: string; 4 | title: string; 5 | author: string; 6 | description: string; 7 | publisher: string; 8 | publishedYear: number; 9 | price: number; 10 | } 11 | -------------------------------------------------------------------------------- /client/src/app/products/products.component.html: -------------------------------------------------------------------------------- 1 |
2 |
4 | 5 |
6 |
7 | Logout 8 |
9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |
Product Name{{row.prodName}}Product Description{{row.prodDesc}}Product Price{{row.prodPrice}}
33 |
34 |
35 | -------------------------------------------------------------------------------- /client/src/app/products/products.component.scss: -------------------------------------------------------------------------------- 1 | /* Structure */ 2 | .example-container { 3 | position: relative; 4 | padding: 5px; 5 | } 6 | 7 | .example-table-container { 8 | position: relative; 9 | max-height: 400px; 10 | overflow: auto; 11 | } 12 | 13 | table { 14 | width: 100%; 15 | } 16 | 17 | .example-loading-shade { 18 | position: absolute; 19 | top: 0; 20 | left: 0; 21 | bottom: 56px; 22 | right: 0; 23 | background: rgba(0, 0, 0, 0.15); 24 | z-index: 1; 25 | display: flex; 26 | align-items: center; 27 | justify-content: center; 28 | } 29 | 30 | .example-rate-limit-reached { 31 | color: #980000; 32 | max-width: 360px; 33 | text-align: center; 34 | } 35 | 36 | /* Column Widths */ 37 | .mat-column-number, 38 | .mat-column-state { 39 | max-width: 64px; 40 | } 41 | 42 | .mat-column-created { 43 | max-width: 124px; 44 | } 45 | 46 | .mat-flat-button { 47 | margin: 5px; 48 | } 49 | -------------------------------------------------------------------------------- /client/src/app/products/products.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ProductsComponent } from './products.component'; 4 | 5 | describe('ProductsComponent', () => { 6 | let component: ProductsComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ProductsComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ProductsComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/products/products.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Product } from './product'; 3 | import { ProductService } from '../product.service'; 4 | import { AuthService } from '../auth.service'; 5 | import { Router } from '@angular/router'; 6 | 7 | @Component({ 8 | selector: 'app-products', 9 | templateUrl: './products.component.html', 10 | styleUrls: ['./products.component.scss'] 11 | }) 12 | export class ProductsComponent implements OnInit { 13 | 14 | data: Product[] = []; 15 | displayedColumns: string[] = ['prodName', 'prodDesc', 'prodPrice']; 16 | isLoadingResults = true; 17 | 18 | constructor(private productService: ProductService, private authService: AuthService, private router: Router) { } 19 | 20 | ngOnInit() { 21 | this.getProducts(); 22 | } 23 | 24 | getProducts(): void { 25 | this.productService.getProducts() 26 | .subscribe(products => { 27 | this.data = products; 28 | console.log(this.data); 29 | this.isLoadingResults = false; 30 | }, err => { 31 | console.log(err); 32 | this.isLoadingResults = false; 33 | }); 34 | } 35 | 36 | logout() { 37 | localStorage.removeItem('token'); 38 | this.router.navigate(['login']); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /client/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didinj/spring-boot-mongodb-security-angular8/bfcaa8b4f82e6eb8302acb69466af1376a13c43b/client/src/assets/.gitkeep -------------------------------------------------------------------------------- /client/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /client/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /client/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didinj/spring-boot-mongodb-security-angular8/bfcaa8b4f82e6eb8302acb69466af1376a13c43b/client/src/favicon.ico -------------------------------------------------------------------------------- /client/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Client 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /client/src/main.ts: -------------------------------------------------------------------------------- 1 | import 'hammerjs'; 2 | import { enableProdMode } from '@angular/core'; 3 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 4 | 5 | import { AppModule } from './app/app.module'; 6 | import { environment } from './environments/environment'; 7 | 8 | if (environment.production) { 9 | enableProdMode(); 10 | } 11 | 12 | platformBrowserDynamic().bootstrapModule(AppModule) 13 | .catch(err => console.error(err)); 14 | -------------------------------------------------------------------------------- /client/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 22 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 23 | 24 | /** 25 | * Web Animations `@angular/platform-browser/animations` 26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 28 | */ 29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 30 | 31 | /** 32 | * By default, zone.js will patch all possible macroTask and DomEvents 33 | * user can disable parts of macroTask/DomEvents patch by setting following flags 34 | * because those flags need to be set before `zone.js` being loaded, and webpack 35 | * will put import in the top of bundle, so user need to create a separate file 36 | * in this directory (for example: zone-flags.ts), and put the following flags 37 | * into that file, and then add the following code before importing zone.js. 38 | * import './zone-flags.ts'; 39 | * 40 | * The flags allowed in zone-flags.ts are listed here. 41 | * 42 | * The following flags will work for all browsers. 43 | * 44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 46 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 47 | * 48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 50 | * 51 | * (window as any).__Zone_enable_cross_context_check = true; 52 | * 53 | */ 54 | 55 | /*************************************************************************************************** 56 | * Zone JS is required by default for Angular itself. 57 | */ 58 | import 'zone.js/dist/zone'; // Included with Angular CLI. 59 | 60 | 61 | /*************************************************************************************************** 62 | * APPLICATION IMPORTS 63 | */ 64 | -------------------------------------------------------------------------------- /client/src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | 3 | html, body { height: 100%; } 4 | body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } 5 | -------------------------------------------------------------------------------- /client/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /client/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/app", 5 | "types": [] 6 | }, 7 | "include": [ 8 | "src/**/*.ts" 9 | ], 10 | "exclude": [ 11 | "src/test.ts", 12 | "src/**/*.spec.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "downlevelIteration": true, 9 | "experimentalDecorators": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "importHelpers": true, 13 | "target": "es2015", 14 | "typeRoots": [ 15 | "node_modules/@types" 16 | ], 17 | "lib": [ 18 | "es2018", 19 | "dom" 20 | ] 21 | }, 22 | "angularCompilerOptions": { 23 | "fullTemplateTypeCheck": true, 24 | "strictInjectionParameters": true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /client/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /client/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended", 3 | "rules": { 4 | "array-type": false, 5 | "arrow-parens": false, 6 | "deprecation": { 7 | "severity": "warning" 8 | }, 9 | "component-class-suffix": true, 10 | "contextual-lifecycle": true, 11 | "directive-class-suffix": true, 12 | "directive-selector": [ 13 | true, 14 | "attribute", 15 | "app", 16 | "camelCase" 17 | ], 18 | "component-selector": [ 19 | true, 20 | "element", 21 | "app", 22 | "kebab-case" 23 | ], 24 | "import-blacklist": [ 25 | true, 26 | "rxjs/Rx" 27 | ], 28 | "interface-name": false, 29 | "max-classes-per-file": false, 30 | "max-line-length": [ 31 | true, 32 | 140 33 | ], 34 | "member-access": false, 35 | "member-ordering": [ 36 | true, 37 | { 38 | "order": [ 39 | "static-field", 40 | "instance-field", 41 | "static-method", 42 | "instance-method" 43 | ] 44 | } 45 | ], 46 | "no-consecutive-blank-lines": false, 47 | "no-console": [ 48 | true, 49 | "debug", 50 | "info", 51 | "time", 52 | "timeEnd", 53 | "trace" 54 | ], 55 | "no-empty": false, 56 | "no-inferrable-types": [ 57 | true, 58 | "ignore-params" 59 | ], 60 | "no-non-null-assertion": true, 61 | "no-redundant-jsdoc": true, 62 | "no-switch-case-fall-through": true, 63 | "no-use-before-declare": true, 64 | "no-var-requires": false, 65 | "object-literal-key-quotes": [ 66 | true, 67 | "as-needed" 68 | ], 69 | "object-literal-sort-keys": false, 70 | "ordered-imports": false, 71 | "quotemark": [ 72 | true, 73 | "single" 74 | ], 75 | "trailing-comma": false, 76 | "no-conflicting-lifecycle": true, 77 | "no-host-metadata-property": true, 78 | "no-input-rename": true, 79 | "no-inputs-metadata-property": true, 80 | "no-output-native": true, 81 | "no-output-on-prefix": true, 82 | "no-output-rename": true, 83 | "no-outputs-metadata-property": true, 84 | "template-banana-in-box": true, 85 | "template-no-negated-async": true, 86 | "use-lifecycle-interface": true, 87 | "use-pipe-transform-interface": true 88 | }, 89 | "rulesDirectory": [ 90 | "codelyzer" 91 | ] 92 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didinj/spring-boot-mongodb-security-angular8/bfcaa8b4f82e6eb8302acb69466af1376a13c43b/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS='"-Xmx64m"' 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS="-Xmx64m" 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | } 5 | } 6 | rootProject.name = 'spring-angular-auth' 7 | -------------------------------------------------------------------------------- /src/main/java/com/djamware/springangularauth/ServletInitializer.java: -------------------------------------------------------------------------------- 1 | package com.djamware.springangularauth; 2 | 3 | import org.springframework.boot.builder.SpringApplicationBuilder; 4 | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; 5 | 6 | public class ServletInitializer extends SpringBootServletInitializer { 7 | 8 | @Override 9 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 10 | return application.sources(SpringAngularAuthApplication.class); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/djamware/springangularauth/SpringAngularAuthApplication.java: -------------------------------------------------------------------------------- 1 | package com.djamware.springangularauth; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class SpringAngularAuthApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(SpringAngularAuthApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/djamware/springangularauth/configs/JwtConfigurer.java: -------------------------------------------------------------------------------- 1 | package com.djamware.springangularauth.configs; 2 | 3 | import org.springframework.security.config.annotation.SecurityConfigurerAdapter; 4 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 5 | import org.springframework.security.web.DefaultSecurityFilterChain; 6 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; 7 | 8 | public class JwtConfigurer extends SecurityConfigurerAdapter { 9 | 10 | private JwtTokenProvider jwtTokenProvider; 11 | 12 | public JwtConfigurer(JwtTokenProvider jwtTokenProvider) { 13 | this.jwtTokenProvider = jwtTokenProvider; 14 | } 15 | 16 | @Override 17 | public void configure(HttpSecurity http) throws Exception { 18 | JwtTokenFilter customFilter = new JwtTokenFilter(jwtTokenProvider); 19 | http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class); 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/java/com/djamware/springangularauth/configs/JwtTokenFilter.java: -------------------------------------------------------------------------------- 1 | 2 | package com.djamware.springangularauth.configs; 3 | 4 | import java.io.IOException; 5 | 6 | import javax.servlet.FilterChain; 7 | import javax.servlet.ServletException; 8 | import javax.servlet.ServletRequest; 9 | import javax.servlet.ServletResponse; 10 | import javax.servlet.http.HttpServletRequest; 11 | 12 | import org.springframework.security.core.Authentication; 13 | import org.springframework.security.core.context.SecurityContextHolder; 14 | import org.springframework.web.filter.GenericFilterBean; 15 | 16 | public class JwtTokenFilter extends GenericFilterBean { 17 | 18 | private JwtTokenProvider jwtTokenProvider; 19 | 20 | public JwtTokenFilter(JwtTokenProvider jwtTokenProvider) { 21 | this.jwtTokenProvider = jwtTokenProvider; 22 | } 23 | 24 | @Override 25 | public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) 26 | throws IOException, ServletException { 27 | String token = jwtTokenProvider.resolveToken((HttpServletRequest) req); 28 | if (token != null && jwtTokenProvider.validateToken(token)) { 29 | Authentication auth = token != null ? jwtTokenProvider.getAuthentication(token) : null; 30 | SecurityContextHolder.getContext().setAuthentication(auth); 31 | } 32 | filterChain.doFilter(req, res); 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/java/com/djamware/springangularauth/configs/JwtTokenProvider.java: -------------------------------------------------------------------------------- 1 | package com.djamware.springangularauth.configs; 2 | 3 | import java.util.Base64; 4 | import java.util.Date; 5 | import java.util.Set; 6 | 7 | import javax.annotation.PostConstruct; 8 | import javax.servlet.http.HttpServletRequest; 9 | 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.beans.factory.annotation.Value; 12 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 13 | import org.springframework.security.core.Authentication; 14 | import org.springframework.security.core.userdetails.UserDetails; 15 | import org.springframework.stereotype.Component; 16 | 17 | import com.djamware.springangularauth.models.Role; 18 | import com.djamware.springangularauth.services.CustomUserDetailsService; 19 | 20 | import io.jsonwebtoken.Claims; 21 | import io.jsonwebtoken.Jws; 22 | import io.jsonwebtoken.JwtException; 23 | import io.jsonwebtoken.Jwts; 24 | import io.jsonwebtoken.SignatureAlgorithm; 25 | 26 | @Component 27 | public class JwtTokenProvider { 28 | 29 | @Value("${security.jwt.token.secret-key:secret}") 30 | private String secretKey = "secret"; 31 | 32 | @Value("${security.jwt.token.expire-length:3600000}") 33 | private long validityInMilliseconds = 3600000; // 1h 34 | 35 | @Autowired 36 | private CustomUserDetailsService userDetailsService; 37 | 38 | @PostConstruct 39 | protected void init() { 40 | secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes()); 41 | } 42 | 43 | public String createToken(String username, Set set) { 44 | Claims claims = Jwts.claims().setSubject(username); 45 | claims.put("roles", set); 46 | Date now = new Date(); 47 | Date validity = new Date(now.getTime() + validityInMilliseconds); 48 | return Jwts.builder()// 49 | .setClaims(claims)// 50 | .setIssuedAt(now)// 51 | .setExpiration(validity)// 52 | .signWith(SignatureAlgorithm.HS256, secretKey)// 53 | .compact(); 54 | } 55 | 56 | public Authentication getAuthentication(String token) { 57 | UserDetails userDetails = this.userDetailsService.loadUserByUsername(getUsername(token)); 58 | return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities()); 59 | } 60 | 61 | public String getUsername(String token) { 62 | return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().getSubject(); 63 | } 64 | 65 | public String resolveToken(HttpServletRequest req) { 66 | String bearerToken = req.getHeader("Authorization"); 67 | if (bearerToken != null && bearerToken.startsWith("Bearer ")) { 68 | return bearerToken.substring(7, bearerToken.length()); 69 | } 70 | return null; 71 | } 72 | 73 | public boolean validateToken(String token) { 74 | try { 75 | Jws claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token); 76 | if (claims.getBody().getExpiration().before(new Date())) { 77 | return false; 78 | } 79 | return true; 80 | } catch (JwtException | IllegalArgumentException e) { 81 | throw new JwtException("Expired or invalid JWT token"); 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /src/main/java/com/djamware/springangularauth/configs/WebSecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.djamware.springangularauth.configs; 2 | 3 | import javax.servlet.http.HttpServletResponse; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.security.authentication.AuthenticationManager; 9 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 10 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 11 | import org.springframework.security.config.annotation.web.builders.WebSecurity; 12 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 13 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 14 | import org.springframework.security.config.http.SessionCreationPolicy; 15 | import org.springframework.security.core.userdetails.UserDetailsService; 16 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 17 | import org.springframework.security.crypto.password.PasswordEncoder; 18 | import org.springframework.security.web.AuthenticationEntryPoint; 19 | 20 | import com.djamware.springangularauth.services.CustomUserDetailsService; 21 | 22 | @Configuration 23 | @EnableWebSecurity 24 | public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 25 | 26 | @Autowired 27 | JwtTokenProvider jwtTokenProvider; 28 | 29 | @Override 30 | protected void configure(AuthenticationManagerBuilder auth) throws Exception { 31 | UserDetailsService userDetailsService = mongoUserDetails(); 32 | auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder()); 33 | 34 | } 35 | 36 | @Override 37 | protected void configure(HttpSecurity http) throws Exception { 38 | http.httpBasic().disable().csrf().disable().sessionManagement() 39 | .sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests() 40 | .antMatchers("/api/auth/login").permitAll().antMatchers("/api/auth/register").permitAll() 41 | .antMatchers("/api/products/**").hasAuthority("ADMIN").anyRequest().authenticated().and().csrf() 42 | .disable().exceptionHandling().authenticationEntryPoint(unauthorizedEntryPoint()).and() 43 | .apply(new JwtConfigurer(jwtTokenProvider)); 44 | http.cors(); 45 | } 46 | 47 | @Override 48 | public void configure(WebSecurity web) throws Exception { 49 | web.ignoring().antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**"); 50 | } 51 | 52 | @Bean 53 | public PasswordEncoder bCryptPasswordEncoder() { 54 | return new BCryptPasswordEncoder(); 55 | } 56 | 57 | @Bean 58 | @Override 59 | public AuthenticationManager authenticationManagerBean() throws Exception { 60 | return super.authenticationManagerBean(); 61 | } 62 | 63 | @Bean 64 | public AuthenticationEntryPoint unauthorizedEntryPoint() { 65 | return (request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED, 66 | "Unauthorized"); 67 | } 68 | 69 | @Bean 70 | public UserDetailsService mongoUserDetails() { 71 | return new CustomUserDetailsService(); 72 | } 73 | } -------------------------------------------------------------------------------- /src/main/java/com/djamware/springangularauth/controllers/AuthBody.java: -------------------------------------------------------------------------------- 1 | package com.djamware.springangularauth.controllers; 2 | 3 | public class AuthBody { 4 | 5 | private String email; 6 | private String password; 7 | 8 | public String getEmail() { 9 | return email; 10 | } 11 | public void setEmail(String email) { 12 | this.email = email; 13 | } 14 | public String getPassword() { 15 | return password; 16 | } 17 | public void setPassword(String password) { 18 | this.password = password; 19 | } 20 | 21 | 22 | } -------------------------------------------------------------------------------- /src/main/java/com/djamware/springangularauth/controllers/AuthController.java: -------------------------------------------------------------------------------- 1 | package com.djamware.springangularauth.controllers; 2 | 3 | import static org.springframework.http.ResponseEntity.ok; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.http.ResponseEntity; 10 | import org.springframework.security.authentication.AuthenticationManager; 11 | import org.springframework.security.authentication.BadCredentialsException; 12 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 13 | import org.springframework.security.core.AuthenticationException; 14 | import org.springframework.web.bind.annotation.CrossOrigin; 15 | import org.springframework.web.bind.annotation.PostMapping; 16 | import org.springframework.web.bind.annotation.RequestBody; 17 | import org.springframework.web.bind.annotation.RequestMapping; 18 | import org.springframework.web.bind.annotation.RestController; 19 | 20 | import com.djamware.springangularauth.configs.JwtTokenProvider; 21 | import com.djamware.springangularauth.models.User; 22 | import com.djamware.springangularauth.repositories.UserRepository; 23 | import com.djamware.springangularauth.services.CustomUserDetailsService; 24 | 25 | 26 | @CrossOrigin(origins = "*") 27 | @RestController 28 | @RequestMapping("/api/auth") 29 | public class AuthController { 30 | 31 | @Autowired 32 | AuthenticationManager authenticationManager; 33 | 34 | @Autowired 35 | JwtTokenProvider jwtTokenProvider; 36 | 37 | @Autowired 38 | UserRepository users; 39 | 40 | @Autowired 41 | private CustomUserDetailsService userService; 42 | 43 | @SuppressWarnings("rawtypes") 44 | @PostMapping("/login") 45 | public ResponseEntity login(@RequestBody AuthBody data) { 46 | try { 47 | String username = data.getEmail(); 48 | authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, data.getPassword())); 49 | String token = jwtTokenProvider.createToken(username, this.users.findByEmail(username).getRoles()); 50 | Map model = new HashMap<>(); 51 | model.put("username", username); 52 | model.put("token", token); 53 | return ok(model); 54 | } catch (AuthenticationException e) { 55 | throw new BadCredentialsException("Invalid email/password supplied"); 56 | } 57 | } 58 | 59 | @SuppressWarnings("rawtypes") 60 | @PostMapping("/register") 61 | public ResponseEntity register(@RequestBody User user) { 62 | User userExists = userService.findUserByEmail(user.getEmail()); 63 | if (userExists != null) { 64 | throw new BadCredentialsException("User with username: " + user.getEmail() + " already exists"); 65 | } 66 | userService.saveUser(user); 67 | Map model = new HashMap<>(); 68 | model.put("message", "User registered successfully"); 69 | return ok(model); 70 | } 71 | } -------------------------------------------------------------------------------- /src/main/java/com/djamware/springangularauth/controllers/ProductController.java: -------------------------------------------------------------------------------- 1 | package com.djamware.springangularauth.controllers; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.web.bind.annotation.CrossOrigin; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RequestMethod; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | import com.djamware.springangularauth.models.Products; 10 | import com.djamware.springangularauth.repositories.ProductRepository; 11 | 12 | @CrossOrigin(origins = "*") 13 | @RequestMapping("/api") 14 | @RestController 15 | public class ProductController { 16 | 17 | @Autowired 18 | ProductRepository productRepository; 19 | 20 | @RequestMapping(method = RequestMethod.GET, value = "/products") 21 | public Iterable product() { 22 | return productRepository.findAll(); 23 | } 24 | } -------------------------------------------------------------------------------- /src/main/java/com/djamware/springangularauth/models/Products.java: -------------------------------------------------------------------------------- 1 | package com.djamware.springangularauth.models; 2 | 3 | import org.springframework.data.annotation.Id; 4 | import org.springframework.data.mongodb.core.mapping.Document; 5 | 6 | @Document(collection = "products") 7 | public class Products { 8 | 9 | @Id 10 | String id; 11 | String prodName; 12 | String prodDesc; 13 | Double prodPrice; 14 | String prodImage; 15 | 16 | public Products() { 17 | } 18 | 19 | public Products(String prodName, String prodDesc, Double prodPrice, String prodImage) { 20 | super(); 21 | this.prodName = prodName; 22 | this.prodDesc = prodDesc; 23 | this.prodPrice = prodPrice; 24 | this.prodImage = prodImage; 25 | } 26 | 27 | public String getId() { 28 | return id; 29 | } 30 | 31 | public void setId(String id) { 32 | this.id = id; 33 | } 34 | 35 | public String getProdName() { 36 | return prodName; 37 | } 38 | 39 | public void setProdName(String prodName) { 40 | this.prodName = prodName; 41 | } 42 | 43 | public String getProdDesc() { 44 | return prodDesc; 45 | } 46 | 47 | public void setProdDesc(String prodDesc) { 48 | this.prodDesc = prodDesc; 49 | } 50 | 51 | public Double getProdPrice() { 52 | return prodPrice; 53 | } 54 | 55 | public void setProdPrice(Double prodPrice) { 56 | this.prodPrice = prodPrice; 57 | } 58 | 59 | public String getProdImage() { 60 | return prodImage; 61 | } 62 | 63 | public void setProdImage(String prodImage) { 64 | this.prodImage = prodImage; 65 | } 66 | 67 | } -------------------------------------------------------------------------------- /src/main/java/com/djamware/springangularauth/models/Role.java: -------------------------------------------------------------------------------- 1 | package com.djamware.springangularauth.models; 2 | 3 | import org.springframework.data.annotation.Id; 4 | import org.springframework.data.mongodb.core.index.IndexDirection; 5 | import org.springframework.data.mongodb.core.index.Indexed; 6 | import org.springframework.data.mongodb.core.mapping.Document; 7 | 8 | @Document(collection = "roles") 9 | public class Role { 10 | 11 | @Id 12 | private String id; 13 | @Indexed(unique = true, direction = IndexDirection.DESCENDING, dropDups = true) 14 | 15 | private String role; 16 | public String getId() { 17 | return id; 18 | } 19 | public void setId(String id) { 20 | this.id = id; 21 | } 22 | public String getRole() { 23 | return role; 24 | } 25 | public void setRole(String role) { 26 | this.role = role; 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /src/main/java/com/djamware/springangularauth/models/User.java: -------------------------------------------------------------------------------- 1 | package com.djamware.springangularauth.models; 2 | 3 | import java.util.Set; 4 | 5 | import org.springframework.data.annotation.Id; 6 | import org.springframework.data.mongodb.core.index.IndexDirection; 7 | import org.springframework.data.mongodb.core.index.Indexed; 8 | import org.springframework.data.mongodb.core.mapping.DBRef; 9 | import org.springframework.data.mongodb.core.mapping.Document; 10 | 11 | @Document(collection = "users") 12 | public class User { 13 | 14 | @Id 15 | private String id; 16 | @Indexed(unique = true, direction = IndexDirection.DESCENDING, dropDups = true) 17 | private String email; 18 | private String password; 19 | private String fullname; 20 | private boolean enabled; 21 | @DBRef 22 | private Set roles; 23 | 24 | public String getId() { 25 | return id; 26 | } 27 | public void setId(String id) { 28 | this.id = id; 29 | } 30 | public String getEmail() { 31 | return email; 32 | } 33 | public void setEmail(String email) { 34 | this.email = email; 35 | } 36 | public String getPassword() { 37 | return password; 38 | } 39 | public void setPassword(String password) { 40 | this.password = password; 41 | } 42 | public String getFullname() { 43 | return fullname; 44 | } 45 | public void setFullname(String fullname) { 46 | this.fullname = fullname; 47 | } 48 | public boolean isEnabled() { 49 | return enabled; 50 | } 51 | public void setEnabled(boolean enabled) { 52 | this.enabled = enabled; 53 | } 54 | public Set getRoles() { 55 | return roles; 56 | } 57 | public void setRoles(Set roles) { 58 | this.roles = roles; 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /src/main/java/com/djamware/springangularauth/repositories/ProductRepository.java: -------------------------------------------------------------------------------- 1 | package com.djamware.springangularauth.repositories; 2 | 3 | import com.djamware.springangularauth.models.Products; 4 | import org.springframework.data.mongodb.repository.MongoRepository; 5 | 6 | public interface ProductRepository extends MongoRepository { 7 | 8 | @Override 9 | void delete(Products deleted); 10 | } -------------------------------------------------------------------------------- /src/main/java/com/djamware/springangularauth/repositories/RoleRepository.java: -------------------------------------------------------------------------------- 1 | package com.djamware.springangularauth.repositories; 2 | 3 | import org.springframework.data.mongodb.repository.MongoRepository; 4 | import com.djamware.springangularauth.models.Role; 5 | 6 | public interface RoleRepository extends MongoRepository { 7 | 8 | Role findByRole(String role); 9 | } -------------------------------------------------------------------------------- /src/main/java/com/djamware/springangularauth/repositories/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.djamware.springangularauth.repositories; 2 | 3 | import com.djamware.springangularauth.models.User; 4 | import org.springframework.data.mongodb.repository.MongoRepository; 5 | 6 | public interface UserRepository extends MongoRepository { 7 | 8 | User findByEmail(String email); 9 | } -------------------------------------------------------------------------------- /src/main/java/com/djamware/springangularauth/services/CustomUserDetailsService.java: -------------------------------------------------------------------------------- 1 | package com.djamware.springangularauth.services; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.HashSet; 6 | import java.util.List; 7 | import java.util.Set; 8 | 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.security.core.GrantedAuthority; 11 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 12 | import org.springframework.security.core.userdetails.UserDetails; 13 | import org.springframework.security.core.userdetails.UserDetailsService; 14 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 15 | import org.springframework.security.crypto.password.PasswordEncoder; 16 | import org.springframework.stereotype.Service; 17 | 18 | import com.djamware.springangularauth.models.Role; 19 | import com.djamware.springangularauth.models.User; 20 | import com.djamware.springangularauth.repositories.RoleRepository; 21 | import com.djamware.springangularauth.repositories.UserRepository; 22 | 23 | @Service 24 | public class CustomUserDetailsService implements UserDetailsService { 25 | 26 | @Autowired 27 | private UserRepository userRepository; 28 | 29 | @Autowired 30 | private RoleRepository roleRepository; 31 | 32 | @Autowired 33 | private PasswordEncoder bCryptPasswordEncoder; 34 | 35 | public User findUserByEmail(String email) { 36 | return userRepository.findByEmail(email); 37 | } 38 | 39 | public void saveUser(User user) { 40 | user.setPassword(bCryptPasswordEncoder.encode(user.getPassword())); 41 | user.setEnabled(true); 42 | Role userRole = roleRepository.findByRole("ADMIN"); 43 | user.setRoles(new HashSet<>(Arrays.asList(userRole))); 44 | userRepository.save(user); 45 | } 46 | 47 | @Override 48 | public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { 49 | 50 | User user = userRepository.findByEmail(email); 51 | if(user != null) { 52 | List authorities = getUserAuthority(user.getRoles()); 53 | return buildUserForAuthentication(user, authorities); 54 | } else { 55 | throw new UsernameNotFoundException("username not found"); 56 | } 57 | } 58 | 59 | private List getUserAuthority(Set userRoles) { 60 | Set roles = new HashSet<>(); 61 | userRoles.forEach((role) -> { 62 | roles.add(new SimpleGrantedAuthority(role.getRole())); 63 | }); 64 | 65 | List grantedAuthorities = new ArrayList<>(roles); 66 | return grantedAuthorities; 67 | } 68 | 69 | private UserDetails buildUserForAuthentication(User user, List authorities) { 70 | return new org.springframework.security.core.userdetails.User(user.getEmail(), user.getPassword(), authorities); 71 | } 72 | } -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.data.mongodb.database=springmongodb 2 | spring.data.mongodb.host=localhost 3 | spring.data.mongodb.port=27017 4 | -------------------------------------------------------------------------------- /src/test/java/com/djamware/springangularauth/SpringAngularAuthApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.djamware.springangularauth; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringAngularAuthApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | --------------------------------------------------------------------------------