Compare commits

...

6 Commits

Author SHA1 Message Date
Chantha
63eee4177a Update implementation JWT complete 2020-05-19 17:15:25 +07:00
Chantha
0db885396d JWT 2020-05-19 17:05:29 +07:00
Chantha
4fce30fdc7 JWT Token 2020-05-19 16:51:38 +07:00
Chantha
0c0dffc6af Register with BCrytEncoder 2020-05-19 15:30:16 +07:00
Chantha
961b318402 Spring Security UserDetailSerivce With ROLE 2020-05-19 13:15:35 +07:00
Chantha
bf58ea2903 "Add Spring Security to project" 2020-05-18 17:11:01 +07:00
42 changed files with 778 additions and 41 deletions

View File

@@ -0,0 +1,13 @@
<component name="libraryTable">
<library name="Maven: io.jsonwebtoken:jjwt:0.9.1">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/jsonwebtoken/jjwt/0.9.1/jjwt-0.9.1.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/jsonwebtoken/jjwt/0.9.1/jjwt-0.9.1-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/jsonwebtoken/jjwt/0.9.1/jjwt-0.9.1-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@@ -0,0 +1,13 @@
<component name="libraryTable">
<library name="Maven: org.attoparser:attoparser:2.0.5.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/attoparser/attoparser/2.0.5.RELEASE/attoparser-2.0.5.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/attoparser/attoparser/2.0.5.RELEASE/attoparser-2.0.5.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/attoparser/attoparser/2.0.5.RELEASE/attoparser-2.0.5.RELEASE-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@@ -0,0 +1,13 @@
<component name="libraryTable">
<library name="Maven: org.springframework.boot:spring-boot-starter-security:2.3.0.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-starter-security/2.3.0.RELEASE/spring-boot-starter-security-2.3.0.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-starter-security/2.3.0.RELEASE/spring-boot-starter-security-2.3.0.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-starter-security/2.3.0.RELEASE/spring-boot-starter-security-2.3.0.RELEASE-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@@ -0,0 +1,13 @@
<component name="libraryTable">
<library name="Maven: org.springframework.boot:spring-boot-starter-thymeleaf:2.3.0.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-starter-thymeleaf/2.3.0.RELEASE/spring-boot-starter-thymeleaf-2.3.0.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-starter-thymeleaf/2.3.0.RELEASE/spring-boot-starter-thymeleaf-2.3.0.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-starter-thymeleaf/2.3.0.RELEASE/spring-boot-starter-thymeleaf-2.3.0.RELEASE-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@@ -0,0 +1,13 @@
<component name="libraryTable">
<library name="Maven: org.springframework.security:spring-security-config:5.2.4.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/security/spring-security-config/5.2.4.RELEASE/spring-security-config-5.2.4.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/security/spring-security-config/5.2.4.RELEASE/spring-security-config-5.2.4.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/security/spring-security-config/5.2.4.RELEASE/spring-security-config-5.2.4.RELEASE-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@@ -0,0 +1,13 @@
<component name="libraryTable">
<library name="Maven: org.springframework.security:spring-security-core:5.2.4.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/security/spring-security-core/5.2.4.RELEASE/spring-security-core-5.2.4.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/security/spring-security-core/5.2.4.RELEASE/spring-security-core-5.2.4.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/security/spring-security-core/5.2.4.RELEASE/spring-security-core-5.2.4.RELEASE-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@@ -0,0 +1,13 @@
<component name="libraryTable">
<library name="Maven: org.springframework.security:spring-security-web:5.2.4.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/security/spring-security-web/5.2.4.RELEASE/spring-security-web-5.2.4.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/security/spring-security-web/5.2.4.RELEASE/spring-security-web-5.2.4.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/security/spring-security-web/5.2.4.RELEASE/spring-security-web-5.2.4.RELEASE-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@@ -0,0 +1,13 @@
<component name="libraryTable">
<library name="Maven: org.thymeleaf.extras:thymeleaf-extras-java8time:3.0.4.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/thymeleaf/extras/thymeleaf-extras-java8time/3.0.4.RELEASE/thymeleaf-extras-java8time-3.0.4.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/thymeleaf/extras/thymeleaf-extras-java8time/3.0.4.RELEASE/thymeleaf-extras-java8time-3.0.4.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/thymeleaf/extras/thymeleaf-extras-java8time/3.0.4.RELEASE/thymeleaf-extras-java8time-3.0.4.RELEASE-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@@ -0,0 +1,13 @@
<component name="libraryTable">
<library name="Maven: org.thymeleaf:thymeleaf:3.0.11.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/thymeleaf/thymeleaf/3.0.11.RELEASE/thymeleaf-3.0.11.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/thymeleaf/thymeleaf/3.0.11.RELEASE/thymeleaf-3.0.11.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/thymeleaf/thymeleaf/3.0.11.RELEASE/thymeleaf-3.0.11.RELEASE-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@@ -0,0 +1,13 @@
<component name="libraryTable">
<library name="Maven: org.thymeleaf:thymeleaf-spring5:3.0.11.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/thymeleaf/thymeleaf-spring5/3.0.11.RELEASE/thymeleaf-spring5-3.0.11.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/thymeleaf/thymeleaf-spring5/3.0.11.RELEASE/thymeleaf-spring5-3.0.11.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/thymeleaf/thymeleaf-spring5/3.0.11.RELEASE/thymeleaf-spring5-3.0.11.RELEASE-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@@ -0,0 +1,13 @@
<component name="libraryTable">
<library name="Maven: org.unbescape:unbescape:1.1.6.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/unbescape/unbescape/1.1.6.RELEASE/unbescape-1.1.6.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/unbescape/unbescape/1.1.6.RELEASE/unbescape-1.1.6.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/unbescape/unbescape/1.1.6.RELEASE/unbescape-1.1.6.RELEASE-sources.jar!/" />
</SOURCES>
</library>
</component>

122
.idea/workspace.xml generated
View File

@@ -2,16 +2,11 @@
<project version="4">
<component name="ChangeListManager">
<list default="true" id="47c3fbf4-4238-47d3-9ffa-fcd23da4e01e" name="Default Changelist" comment="">
<change afterPath="$PROJECT_DIR$/src/main/kotlin/com/chantha/jdbc/config/WebConfig.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/kotlin/com/chantha/jdbc/jpa/model/Position.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/kotlin/com/chantha/jdbc/jpa/model/Staff.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pom.xml" beforeDir="false" afterPath="$PROJECT_DIR$/pom.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/kotlin/com/chantha/jdbc/controller/ProductController.kt" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/kotlin/com/chantha/jdbc/controller/ProductController.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/kotlin/com/chantha/jdbc/jpa/model/Customer.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/kotlin/com/chantha/jdbc/jpa/model/Customer.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/kotlin/com/chantha/jdbc/jpa/model/Order.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/kotlin/com/chantha/jdbc/jpa/model/Order.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/target/classes/com/chantha/jdbc/controller/ProductController.class" beforeDir="false" afterPath="$PROJECT_DIR$/target/classes/com/chantha/jdbc/controller/ProductController.class" afterDir="false" />
<change beforePath="$PROJECT_DIR$/target/classes/com/chantha/jdbc/jpa/model/Order.class" beforeDir="false" afterPath="$PROJECT_DIR$/target/classes/com/chantha/jdbc/jpa/model/Order.class" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/kotlin/com/chantha/jdbc/config/WebConfig.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/kotlin/com/chantha/jdbc/config/WebConfig.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/resources/application.properties" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/resources/application.properties" afterDir="false" />
<change beforePath="$PROJECT_DIR$/target/classes/application.properties" beforeDir="false" afterPath="$PROJECT_DIR$/target/classes/application.properties" afterDir="false" />
<change beforePath="$PROJECT_DIR$/target/classes/com/chantha/jdbc/config/WebConfig.class" beforeDir="false" afterPath="$PROJECT_DIR$/target/classes/com/chantha/jdbc/config/WebConfig.class" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -22,8 +17,9 @@
<option name="RECENT_TEMPLATES">
<list>
<option value="Interface" />
<option value="Kotlin Interface" />
<option value="Kotlin Class" />
<option value="Kotlin Interface" />
<option value="HTML File" />
<option value="Kotlin File" />
<option value="Class" />
</list>
@@ -33,6 +29,13 @@
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
<option name="UPDATE_TYPE" value="MERGE" />
</component>
<component name="MavenImportPreferences">
<option name="importingSettings">
<MavenImportingSettings>
<option name="importAutomatically" value="true" />
</MavenImportingSettings>
</option>
</component>
<component name="ProjectId" id="1bvsGR0v8LaFrgE2379EYP5rUBj" />
<component name="ProjectLevelVcsManager" settingsEditedManually="true">
<ConfirmationsSetting value="2" id="Add" />
@@ -43,6 +46,7 @@
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">
<property name="DefaultHtmlFileTemplate" value="HTML File" />
<property name="RequestMappingsPanelOrder0" value="0" />
<property name="RequestMappingsPanelOrder1" value="1" />
<property name="RequestMappingsPanelWidth0" value="75" />
@@ -51,7 +55,7 @@
<property name="SHARE_PROJECT_CONFIGURATION_FILES" value="true" />
<property name="WebServerToolWindowFactoryState" value="false" />
<property name="aspect.path.notification.shown" value="true" />
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
<property name="last_opened_file_path" value="$PROJECT_DIR$/../spring-boot-react-oauth2-social-login-demo/spring-social" />
<property name="restartRequiresConfirmation" value="false" />
</component>
<component name="RecentsManager">
@@ -90,13 +94,27 @@
<workItem from="1589690218526" duration="3238000" />
<workItem from="1589695280458" duration="9667000" />
<workItem from="1589774040527" duration="72000" />
<workItem from="1589788206287" duration="48000" />
<workItem from="1589788206287" duration="4024000" />
<workItem from="1589857721932" duration="2546000" />
<workItem from="1589862025987" duration="18632000" />
</task>
<task id="LOCAL-00001" summary="&quot;Add Spring Security to project&quot;">
<created>1589796661163</created>
<option name="number" value="00001" />
<option name="presentableId" value="LOCAL-00001" />
<option name="project" value="LOCAL" />
<updated>1589796661163</updated>
</task>
<option name="localTasksCounter" value="2" />
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="1" />
</component>
<component name="VcsManagerConfiguration">
<MESSAGE value="&quot;Add Spring Security to project&quot;" />
<option name="LAST_COMMIT_MESSAGE" value="&quot;Add Spring Security to project&quot;" />
</component>
<component name="WindowStateProjectService">
<state x="552" y="179" key="#Auto_Import" timestamp="1589535953579">
<screen x="0" y="0" width="1920" height="1040" />
@@ -106,10 +124,14 @@
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state x="690" y="276" key="#com.intellij.codeInsight.editorActions.RestoreReferencesDialog/0.0.1920.1040@0.0.1920.1040" timestamp="1589601961718" />
<state x="765" y="197" key="#com.intellij.ide.util.MemberChooser" timestamp="1589700451727">
<state x="414" y="176" key="#com.intellij.execution.impl.EditConfigurationsDialog" timestamp="1589880612427">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state x="765" y="197" key="#com.intellij.ide.util.MemberChooser/0.0.1920.1040@0.0.1920.1040" timestamp="1589700451727" />
<state x="414" y="176" key="#com.intellij.execution.impl.EditConfigurationsDialog/0.0.1920.1040@0.0.1920.1040" timestamp="1589880612427" />
<state x="765" y="197" key="#com.intellij.ide.util.MemberChooser" timestamp="1589863580998">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state x="765" y="197" key="#com.intellij.ide.util.MemberChooser/0.0.1920.1040@0.0.1920.1040" timestamp="1589863580998" />
<state x="649" y="437" key="#com.intellij.refactoring.move.MoveHandler.SelectRefactoringDialog" timestamp="1589690277066">
<screen x="0" y="0" width="1920" height="1040" />
</state>
@@ -122,49 +144,77 @@
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state x="739" y="31" key="#org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui.MoveKotlinTopLevelDeclarationsDialog/0.0.1920.1040@0.0.1920.1040" timestamp="1589608464352" />
<state x="740" y="276" key="FileChooserDialogImpl" timestamp="1589774110803">
<state x="508" y="29" key="CommitChangelistDialog2" timestamp="1589796659997">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state x="740" y="276" key="FileChooserDialogImpl/0.0.1920.1040@0.0.1920.1040" timestamp="1589774110803" />
<state width="1877" height="420" key="GridCell.Tab.0.bottom" timestamp="1589709359957">
<state x="508" y="29" key="CommitChangelistDialog2/0.0.1920.1040@0.0.1920.1040" timestamp="1589796659997" />
<state x="740" y="276" key="FileChooserDialogImpl" timestamp="1589879048291">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state width="1877" height="420" key="GridCell.Tab.0.bottom/0.0.1920.1040@0.0.1920.1040" timestamp="1589709359957" />
<state width="1877" height="420" key="GridCell.Tab.0.center" timestamp="1589709359957">
<state x="740" y="276" key="FileChooserDialogImpl/0.0.1920.1040@0.0.1920.1040" timestamp="1589879048291" />
<state width="1877" height="420" key="GridCell.Tab.0.bottom" timestamp="1589883286029">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state width="1877" height="420" key="GridCell.Tab.0.center/0.0.1920.1040@0.0.1920.1040" timestamp="1589709359957" />
<state width="1877" height="420" key="GridCell.Tab.0.left" timestamp="1589709359957">
<state width="1877" height="420" key="GridCell.Tab.0.bottom/0.0.1920.1040@0.0.1920.1040" timestamp="1589883286029" />
<state width="1877" height="420" key="GridCell.Tab.0.center" timestamp="1589883286029">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state width="1877" height="420" key="GridCell.Tab.0.left/0.0.1920.1040@0.0.1920.1040" timestamp="1589709359957" />
<state width="1877" height="420" key="GridCell.Tab.0.right" timestamp="1589709359957">
<state width="1877" height="420" key="GridCell.Tab.0.center/0.0.1920.1040@0.0.1920.1040" timestamp="1589883286029" />
<state width="1877" height="420" key="GridCell.Tab.0.left" timestamp="1589883286029">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state width="1877" height="420" key="GridCell.Tab.0.right/0.0.1920.1040@0.0.1920.1040" timestamp="1589709359957" />
<state width="1877" height="420" key="GridCell.Tab.1.bottom" timestamp="1589709359958">
<state width="1877" height="420" key="GridCell.Tab.0.left/0.0.1920.1040@0.0.1920.1040" timestamp="1589883286029" />
<state width="1877" height="420" key="GridCell.Tab.0.right" timestamp="1589883286029">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state width="1877" height="420" key="GridCell.Tab.1.bottom/0.0.1920.1040@0.0.1920.1040" timestamp="1589709359958" />
<state width="1877" height="420" key="GridCell.Tab.1.center" timestamp="1589709359957">
<state width="1877" height="420" key="GridCell.Tab.0.right/0.0.1920.1040@0.0.1920.1040" timestamp="1589883286029" />
<state width="1877" height="420" key="GridCell.Tab.1.bottom" timestamp="1589883286030">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state width="1877" height="420" key="GridCell.Tab.1.center/0.0.1920.1040@0.0.1920.1040" timestamp="1589709359957" />
<state width="1877" height="420" key="GridCell.Tab.1.left" timestamp="1589709359957">
<state width="1877" height="420" key="GridCell.Tab.1.bottom/0.0.1920.1040@0.0.1920.1040" timestamp="1589883286030" />
<state width="1877" height="420" key="GridCell.Tab.1.center" timestamp="1589883286029">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state width="1877" height="420" key="GridCell.Tab.1.left/0.0.1920.1040@0.0.1920.1040" timestamp="1589709359957" />
<state width="1877" height="420" key="GridCell.Tab.1.right" timestamp="1589709359958">
<state width="1877" height="420" key="GridCell.Tab.1.center/0.0.1920.1040@0.0.1920.1040" timestamp="1589883286029" />
<state width="1877" height="420" key="GridCell.Tab.1.left" timestamp="1589883286029">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state width="1877" height="420" key="GridCell.Tab.1.right/0.0.1920.1040@0.0.1920.1040" timestamp="1589709359958" />
<state x="767" y="433" key="com.intellij.openapi.vcs.update.UpdateOrStatusOptionsDialogupdate-v2" timestamp="1589538516704">
<state width="1877" height="420" key="GridCell.Tab.1.left/0.0.1920.1040@0.0.1920.1040" timestamp="1589883286029" />
<state width="1877" height="420" key="GridCell.Tab.1.right" timestamp="1589883286029">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state x="767" y="433" key="com.intellij.openapi.vcs.update.UpdateOrStatusOptionsDialogupdate-v2/0.0.1920.1040@0.0.1920.1040" timestamp="1589538516704" />
<state x="623" y="225" width="672" height="678" key="search.everywhere.popup" timestamp="1589699975397">
<state width="1877" height="420" key="GridCell.Tab.1.right/0.0.1920.1040@0.0.1920.1040" timestamp="1589883286029" />
<state width="1877" height="326" key="GridCell.Tab.2.bottom" timestamp="1589796703748">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state x="623" y="225" width="672" height="678" key="search.everywhere.popup/0.0.1920.1040@0.0.1920.1040" timestamp="1589699975397" />
<state width="1877" height="326" key="GridCell.Tab.2.bottom/0.0.1920.1040@0.0.1920.1040" timestamp="1589796703748" />
<state width="1877" height="326" key="GridCell.Tab.2.center" timestamp="1589796703748">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state width="1877" height="326" key="GridCell.Tab.2.center/0.0.1920.1040@0.0.1920.1040" timestamp="1589796703748" />
<state width="1877" height="326" key="GridCell.Tab.2.left" timestamp="1589796703748">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state width="1877" height="326" key="GridCell.Tab.2.left/0.0.1920.1040@0.0.1920.1040" timestamp="1589796703748" />
<state width="1877" height="326" key="GridCell.Tab.2.right" timestamp="1589796703748">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state width="1877" height="326" key="GridCell.Tab.2.right/0.0.1920.1040@0.0.1920.1040" timestamp="1589796703748" />
<state x="767" y="433" key="com.intellij.openapi.vcs.update.UpdateOrStatusOptionsDialogupdate-v2" timestamp="1589796631131">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state x="767" y="433" key="com.intellij.openapi.vcs.update.UpdateOrStatusOptionsDialogupdate-v2/0.0.1920.1040@0.0.1920.1040" timestamp="1589796631131" />
<state x="342" y="100" key="new project wizard" timestamp="1589876220249">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state x="342" y="100" key="new project wizard/0.0.1920.1040@0.0.1920.1040" timestamp="1589876220249" />
<state x="616" y="240" key="run.anything.popup" timestamp="1589796621453">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state x="616" y="240" key="run.anything.popup/0.0.1920.1040@0.0.1920.1040" timestamp="1589796621453" />
<state x="623" y="225" width="672" height="678" key="search.everywhere.popup" timestamp="1589877750441">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state x="623" y="225" width="672" height="678" key="search.everywhere.popup/0.0.1920.1040@0.0.1920.1040" timestamp="1589877750441" />
</component>
</project>

View File

@@ -71,7 +71,6 @@
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-jpa:2.2.7.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-aop:2.2.7.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.aspectj:aspectjweaver:1.9.5" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.2.7.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.zaxxer:HikariCP:3.4.3" level="project" />
@@ -130,6 +129,17 @@
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.10.4" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.10.4" level="project" />
<orderEntry type="library" name="Maven: org.postgresql:postgresql:42.2.12" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-thymeleaf:2.3.0.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.thymeleaf:thymeleaf-spring5:3.0.11.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.thymeleaf:thymeleaf:3.0.11.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.attoparser:attoparser:2.0.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.unbescape:unbescape:1.1.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.thymeleaf.extras:thymeleaf-extras-java8time:3.0.4.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-security:2.3.0.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-config:5.2.4.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-core:5.2.4.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-web:5.2.4.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-reflect:1.3.72" level="project" />
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib:1.3.72" level="project" />
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72" level="project" />
@@ -166,5 +176,6 @@
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.2.6.RELEASE" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework:spring-test:5.2.6.RELEASE" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.xmlunit:xmlunit-core:2.6.4" level="project" />
<orderEntry type="library" name="Maven: io.jsonwebtoken:jjwt:0.9.1" level="project" />
</component>
</module>

13
pom.xml
View File

@@ -38,6 +38,13 @@
<artifactId>postgresql</artifactId>
<version>42.2.12</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.3.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-security -->
<dependency>
@@ -45,7 +52,6 @@
<artifactId>spring-boot-starter-security</artifactId>
<version>2.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
@@ -71,6 +77,11 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
</dependencies>
<build>

View File

@@ -1,4 +1,66 @@
package com.chantha.jdbc.config;
public class WebConfig {
import com.chantha.jdbc.utils.jwt.JwtRequestFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@Configuration
@EnableWebSecurity
public class WebConfig extends WebSecurityConfigurerAdapter {
private final UserDetailsService userDetailsService;
@Autowired
private JwtRequestFilter jwtRequestFilter;
@Autowired
public WebConfig(UserDetailsService userDetailsService){
this.userDetailsService=userDetailsService;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin();
http.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
http.authorizeRequests()
.antMatchers("/register").permitAll();
// .antMatchers("/**").hasAnyRole("ADMIN");
http.csrf().disable();
http.addFilterBefore(jwtRequestFilter,UsernamePasswordAuthenticationFilter.class);
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}

View File

@@ -0,0 +1,37 @@
package com.chantha.jdbc.controller
import com.chantha.jdbc.security.User
import com.chantha.jdbc.security.UserRepo
import com.sun.istack.NotNull
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.ModelAttribute
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestParam
@Controller
class UserController @Autowired constructor(private val userRepo: UserRepo){
fun encoder():BCryptPasswordEncoder{
return BCryptPasswordEncoder()
}
@GetMapping("/register")
fun register():String{
return "register"
}
@PostMapping("/register")
fun saveRegister(@NotNull @ModelAttribute("user") user:User?):String{
user!!.password=encoder().encode(user.password)
user.roles="ROLES_${user.roles}"
userRepo.save(user)
return "register"
}
}

View File

@@ -0,0 +1,28 @@
package com.chantha.jdbc.security
import javax.persistence.*
@Suppress("UNCHECKED_CAST")
@Entity
@Table(name = "tbUser")
data class User(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
var userId:Long ? = 0 ,
@Column(nullable = false,unique = true)
var userName:String,
@Column(nullable = false,unique = true)
var password:String,
var roles:String,
var status:Int ?= 1
)
{
fun getRolesList():List<String>{
if(roles.isNotEmpty()){
return roles.split("_")
}
return listOf()
}
}

View File

@@ -0,0 +1,17 @@
package com.chantha.jdbc.security
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.core.userdetails.UsernameNotFoundException
import org.springframework.stereotype.Service
@Service
class UserDetailServiceImpl @Autowired constructor(private val userRepo: UserRepo):UserDetailsService {
@Throws(UsernameNotFoundException::class)
override fun loadUserByUsername(p0: String?): UserDetails {
val user = userRepo.findByUsername(p0!!)
return UserPrincipal(user)
}
}

View File

@@ -0,0 +1,47 @@
package com.chantha.jdbc.security
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.security.core.GrantedAuthority
import org.springframework.security.core.authority.SimpleGrantedAuthority
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.stereotype.Component
import org.springframework.stereotype.Controller
import org.springframework.stereotype.Service
class UserPrincipal constructor(private val user: User):UserDetails{
override fun getAuthorities(): List<GrantedAuthority> {
val listGrantedAuthority= mutableListOf<GrantedAuthority>()
user.getRolesList().map {
val roles=SimpleGrantedAuthority("ROLE_$it")
listGrantedAuthority.add(roles)
}
return listGrantedAuthority
}
override fun isEnabled(): Boolean {
return user.status == 1
}
override fun getUsername(): String {
return user.userName
}
override fun isCredentialsNonExpired(): Boolean {
return true
}
override fun getPassword(): String {
return user.password
}
override fun isAccountNonExpired(): Boolean {
return true
}
override fun isAccountNonLocked(): Boolean {
return true
}
}

View File

@@ -0,0 +1,11 @@
package com.chantha.jdbc.security
import org.springframework.data.jpa.repository.Query
import org.springframework.data.repository.CrudRepository
import org.springframework.stereotype.Repository
@Repository
interface UserRepo : CrudRepository<User,Long>{
@Query("SELECT * FROM tb_user WHERE user_name = :user ",nativeQuery = true)
fun findByUsername(user:String):User
}

View File

@@ -0,0 +1,49 @@
package com.chantha.jdbc.utils.jwt;
import java.util.Objects;
import com.chantha.jdbc.security.UserDetailServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@CrossOrigin
public class JwtAuthenticationController {
private AuthenticationManager authenticationManager;
private JwtTokenUtil jwtTokenUtil;
private UserDetailServiceImpl userDetailsService;
@Autowired
public JwtAuthenticationController(AuthenticationManager authenticationManager,UserDetailServiceImpl userDetailsService,JwtTokenUtil jwtTokenUtil){
this.authenticationManager=authenticationManager;
this.jwtTokenUtil=jwtTokenUtil;
this.userDetailsService=userDetailsService;
}
@RequestMapping(value = "/authenticate", method = RequestMethod.POST)
public ResponseEntity<?> createAuthenticationToken(@RequestBody JwtRequest authenticationRequest) throws Exception {
authenticate(authenticationRequest.getUsername(), authenticationRequest.getPassword());
final UserDetails userDetails = userDetailsService
.loadUserByUsername(authenticationRequest.getUsername());
final String token = jwtTokenUtil.generateToken(userDetails);
return ResponseEntity.ok(new JwtResponse(token));
}
private void authenticate(String username, String password) throws Exception {
try {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
} catch (DisabledException e) {
throw new Exception("USER_DISABLED", e);
} catch (BadCredentialsException e) {
throw new Exception("INVALID_CREDENTIALS", e);
}
}
}

View File

@@ -0,0 +1,19 @@
package com.chantha.jdbc.utils.jwt;
import java.io.IOException;
import java.io.Serializable;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable {
private static final long serialVersionUID = -7858869558953243875L;
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}

View File

@@ -0,0 +1,28 @@
package com.chantha.jdbc.utils.jwt;
import java.io.Serializable;
public class JwtRequest implements Serializable {
private static final long serialVersionUID = 5926468583005150707L;
private String username;
private String password;
//need default constructor for JSON Parsing
public JwtRequest()
{
}
public JwtRequest(String username, String password) {
this.setUsername(username);
this.setPassword(password);
}
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
}

View File

@@ -0,0 +1,63 @@
package com.chantha.jdbc.utils.jwt;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import com.chantha.jdbc.security.UserDetailServiceImpl;
import io.jsonwebtoken.ExpiredJwtException;
@Component
public class JwtRequestFilter extends OncePerRequestFilter {
@Autowired
private UserDetailServiceImpl jwtUserDetailsService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
final String requestTokenHeader = request.getHeader("Authorization");
String username = null;
String jwtToken = null;
// JWT Token is in the form "Bearer token". Remove Bearer word and get
// only the Token
if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
jwtToken = requestTokenHeader.substring(7);
try {
username = jwtTokenUtil.getUsernameFromToken(jwtToken);
} catch (IllegalArgumentException e) {
System.out.println("Unable to get JWT Token");
} catch (ExpiredJwtException e) {
System.out.println("JWT Token has expired");
}
} else {
logger.warn("JWT Token does not begin with Bearer String");
}
// Once we get the token validate it.
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.jwtUserDetailsService.loadUserByUsername(username);
// if token is valid configure Spring Security to manually set
// authentication
if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
// After setting the Authentication in the context, we specify
// that the current user is authenticated. So it passes the
// Spring Security Configurations successfully.
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
chain.doFilter(request, response);
}
}

View File

@@ -0,0 +1,16 @@
package com.chantha.jdbc.utils.jwt;
import java.io.Serializable;
public class JwtResponse implements Serializable {
private static final long serialVersionUID = -8091879091924046844L;
private final String jwttoken;
public JwtResponse(String jwttoken) {
this.jwttoken = jwttoken;
}
public String getToken() {
return this.jwttoken;
}
}

View File

@@ -0,0 +1,63 @@
package com.chantha.jdbc.utils.jwt;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
@Component
public class JwtTokenUtil implements Serializable {
private static final long serialVersionUID = -2550185165626007488L;
public static final long JWT_TOKEN_VALIDITY = 5 * 60 * 60;
@Value("${jwt.secret}")
private String secret;
//retrieve username from jwt token
public String getUsernameFromToken(String token) {
return getClaimFromToken(token, Claims::getSubject);
}
//retrieve expiration date from jwt token
public Date getExpirationDateFromToken(String token) {
return getClaimFromToken(token, Claims::getExpiration);
}
public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
final Claims claims = getAllClaimsFromToken(token);
return claimsResolver.apply(claims);
}
//for retrieveing any information from token we will need the secret key
private Claims getAllClaimsFromToken(String token) {
return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
}
//check if the token has expired
private Boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(new Date());
}
//generate token for user
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return doGenerateToken(claims, userDetails.getUsername());
}
//while creating the token -
//1. Define claims of the token, like Issuer, Expiration, Subject, and the ID
//2. Sign the JWT using the HS512 algorithm and secret key.
//3. According to JWS Compact Serialization(https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-41#section-3.1)
// compaction of the JWT to a URL-safe string
private String doGenerateToken(Map<String, Object> claims, String subject) {
return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + JWT_TOKEN_VALIDITY * 1000))
.signWith(SignatureAlgorithm.HS512, secret).compact();
}
//validate token
public Boolean validateToken(String token, UserDetails userDetails) {
final String username = getUsernameFromToken(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
}

View File

@@ -4,7 +4,10 @@ spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=update
spring.jpa.open-in-view=true
server.port=8081
spring.thymeleaf.cache=true
jwt.secret=$uonCh@nTh@

View File

@@ -0,0 +1,38 @@
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
</head>
<body>
<div style="width: 200px; margin: auto; top: 500px ; ">
<form class="form-horizontal" th:action="@{/register}" th:method="POST" th:object="${user}">
<div class="form-group">
<label for="usr">Name:</label>
<input type="text" class="form-control" id="usr" th:name="userName">
</div>
<div class="form-group">
<label for="pwd">Password:</label>
<input type="password" class="form-control" id="pwd" th:name="password">
</div>
<div class="form-group">
<label for="sel1">Select list:</label>
<select class="form-control" id="sel1" th:name="roles">
<option th:value="Choose">Choose</option>
<option th:value="ADMIN">ADMIN</option>
<option th:value="DBA">DBA</option>
<option th:value="USER">USER</option>
</select>
</div>
<div class="form-group">
<button type="submit" class="btn btn-success">Success</button>
</div>
</form>
</div>
</body>
</html>

View File

@@ -4,7 +4,10 @@ spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=update
spring.jpa.open-in-view=true
server.port=8081
spring.thymeleaf.cache=true
jwt.secret=$uonCh@nTh@

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,38 @@
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
</head>
<body>
<div style="width: 200px; margin: auto; top: 500px ; ">
<form class="form-horizontal" th:action="@{/register}" th:method="POST" th:object="${user}">
<div class="form-group">
<label for="usr">Name:</label>
<input type="text" class="form-control" id="usr" th:name="userName">
</div>
<div class="form-group">
<label for="pwd">Password:</label>
<input type="password" class="form-control" id="pwd" th:name="password">
</div>
<div class="form-group">
<label for="sel1">Select list:</label>
<select class="form-control" id="sel1" th:name="roles">
<option th:value="Choose">Choose</option>
<option th:value="ADMIN">ADMIN</option>
<option th:value="DBA">DBA</option>
<option th:value="USER">USER</option>
</select>
</div>
<div class="form-group">
<button type="submit" class="btn btn-success">Success</button>
</div>
</form>
</div>
</body>
</html>