From 961b318402e107371f3fdbfe1d7f2804e7c6d470 Mon Sep 17 00:00:00 2001 From: Chantha Date: Tue, 19 May 2020 13:15:35 +0700 Subject: [PATCH] Spring Security UserDetailSerivce With ROLE --- .idea/workspace.xml | 99 ++++++++++-------- .../com/chantha/jdbc/config/WebConfig.java | 29 +++-- .../kotlin/com/chantha/jdbc/security/User.kt | 28 +++++ .../jdbc/security/UserDetailServiceImpl.kt | 14 +++ .../chantha/jdbc/security/UserPrincipal.kt | 47 +++++++++ .../com/chantha/jdbc/security/UserRepo.kt | 11 ++ target/classes/application.properties | 2 +- .../com/chantha/jdbc/config/WebConfig.class | Bin 0 -> 3736 bytes .../com/chantha/jdbc/security/User.class | Bin 0 -> 5629 bytes .../jdbc/security/UserDetailServiceImpl.class | Bin 0 -> 2076 bytes .../chantha/jdbc/security/UserPrincipal.class | Bin 0 -> 4020 bytes .../com/chantha/jdbc/security/UserRepo.class | Bin 0 -> 1181 bytes 12 files changed, 180 insertions(+), 50 deletions(-) create mode 100644 src/main/kotlin/com/chantha/jdbc/security/User.kt create mode 100644 src/main/kotlin/com/chantha/jdbc/security/UserDetailServiceImpl.kt create mode 100644 src/main/kotlin/com/chantha/jdbc/security/UserPrincipal.kt create mode 100644 src/main/kotlin/com/chantha/jdbc/security/UserRepo.kt create mode 100644 target/classes/com/chantha/jdbc/config/WebConfig.class create mode 100644 target/classes/com/chantha/jdbc/security/User.class create mode 100644 target/classes/com/chantha/jdbc/security/UserDetailServiceImpl.class create mode 100644 target/classes/com/chantha/jdbc/security/UserPrincipal.class create mode 100644 target/classes/com/chantha/jdbc/security/UserRepo.class diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 63f85e0..d14b2aa 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -2,14 +2,13 @@ - - - - + + + + - - + @@ -56,7 +55,7 @@ - + @@ -95,13 +94,27 @@ - + + + + + 1589796661163 + + + + + @@ -111,10 +124,10 @@ - + - + @@ -127,58 +140,62 @@ - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + + + + + @@ -187,9 +204,9 @@ - + - + \ No newline at end of file diff --git a/src/main/kotlin/com/chantha/jdbc/config/WebConfig.java b/src/main/kotlin/com/chantha/jdbc/config/WebConfig.java index fd9f8b4..f3620df 100644 --- a/src/main/kotlin/com/chantha/jdbc/config/WebConfig.java +++ b/src/main/kotlin/com/chantha/jdbc/config/WebConfig.java @@ -1,27 +1,40 @@ package com.chantha.jdbc.config; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +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.web.util.matcher.AntPathRequestMatcher; +@Configuration +@EnableWebSecurity public class WebConfig extends WebSecurityConfigurerAdapter { - @Override - public void configure(WebSecurity web) throws Exception { + private final UserDetailsService userDetailsService; - UserDetails user= User.builder() - .username("chantha") - .password("chantha") - .roles("ADMIN") - .build(); + @Autowired + public WebConfig(UserDetailsService userDetailsService){ + this.userDetailsService=userDetailsService; + } + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.userDetailsService(userDetailsService); } @Override protected void configure(HttpSecurity http) throws Exception { http.formLogin(); - http.cors().disable(); + http.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")); + http.authorizeRequests() + .antMatchers("/**").hasAnyRole("ADMIN"); + http.csrf().disable(); } diff --git a/src/main/kotlin/com/chantha/jdbc/security/User.kt b/src/main/kotlin/com/chantha/jdbc/security/User.kt new file mode 100644 index 0000000..5a1c2f7 --- /dev/null +++ b/src/main/kotlin/com/chantha/jdbc/security/User.kt @@ -0,0 +1,28 @@ +package com.chantha.jdbc.security + +import javax.persistence.* + + +@Suppress("UNCHECKED_CAST") +@Entity +@Table(name = "tbUser") +data class User( + @Id + @GeneratedValue + var userId:Long , + @Column(nullable = false,unique = true) + var userName:String, + @Column(nullable = false,unique = true) + var password:String, + var roles:String, + var status:Int + +) +{ + fun getRolesList():List{ + if(roles.isNotEmpty()){ + return roles.split("_") + } + return listOf() + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/chantha/jdbc/security/UserDetailServiceImpl.kt b/src/main/kotlin/com/chantha/jdbc/security/UserDetailServiceImpl.kt new file mode 100644 index 0000000..f466183 --- /dev/null +++ b/src/main/kotlin/com/chantha/jdbc/security/UserDetailServiceImpl.kt @@ -0,0 +1,14 @@ +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.stereotype.Service + +@Service +class UserDetailServiceImpl @Autowired constructor(private val userRepo: UserRepo):UserDetailsService { + override fun loadUserByUsername(p0: String?): UserDetails { + val user=userRepo.findByUsername(p0!!) + return UserPrincipal(user) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/chantha/jdbc/security/UserPrincipal.kt b/src/main/kotlin/com/chantha/jdbc/security/UserPrincipal.kt new file mode 100644 index 0000000..c7997dd --- /dev/null +++ b/src/main/kotlin/com/chantha/jdbc/security/UserPrincipal.kt @@ -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 { + val listGrantedAuthority= mutableListOf() + 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 "{noop}${user.password}" + } + + override fun isAccountNonExpired(): Boolean { + return true + } + + override fun isAccountNonLocked(): Boolean { + return true + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/chantha/jdbc/security/UserRepo.kt b/src/main/kotlin/com/chantha/jdbc/security/UserRepo.kt new file mode 100644 index 0000000..612b59e --- /dev/null +++ b/src/main/kotlin/com/chantha/jdbc/security/UserRepo.kt @@ -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{ + @Query("SELECT * FROM tb_user WHERE user_name = :user ",nativeQuery = true) + fun findByUsername(user:String):User +} \ No newline at end of file diff --git a/target/classes/application.properties b/target/classes/application.properties index c76806f..ad18dc6 100644 --- a/target/classes/application.properties +++ b/target/classes/application.properties @@ -4,7 +4,7 @@ spring.datasource.password=root spring.jpa.hibernate.ddl-auto=update spring.jpa.open-in-view=true - +server.port=8081 diff --git a/target/classes/com/chantha/jdbc/config/WebConfig.class b/target/classes/com/chantha/jdbc/config/WebConfig.class new file mode 100644 index 0000000000000000000000000000000000000000..d6c31806c7bbea0b866a54ce4e1cc7bfd738fefa GIT binary patch literal 3736 zcmc&%ZC4vb6n+K*3u#K*l(x3EY6Wcw+V!Pkl@<&E1WXDgyoj~xWHTg-VVBO%7Vx7V z^s^uR8J?qXjvhUJ_D6ZVvzw45rXZx}cyjjT&d%KX+~>Z` z#_<;3j^iD?t8aGjy_E4Pg8MB<6{Fe z24)$Oz9;0QP~5J11tFi>mSC93xw33}TheyQ>ymGZZC8G6dcyLht#(bzmBQ5PO5r+l z`CmFl8M^P;j;+QRrc&*z8(LwAW!(~iJD0N^@xb3K3c19KRT@d=T#Hv%xU{ug8;q%n z?J*4GEO*niD%?>OZf=x{7QuJc?XtNlirL_eu%6EgRdGuTTsy0Tq=i=(eMi}wV#W4s z(wcD`S8-*#4t=}Z(xIZ@j%TiOOSy8_J6>?l5kg!B_;qG(ZqdK z5d_N$keEf^u9gU`wh$T5bBC9OoCv>;2HfeD45B6QNMN6fL5BF$jwQANwhYWMo`JYtK9Phm2OvNGCxaHeSt3%_zK)WF#!uDhMUJW3WmpRI26V* z62*oOnG)ZkuETJ#LFz#T5w9s-!qjz-?8(ogbQ$)Kt<>Xt|IkTOUN@&mTdQZkPJ!q) zGs#^Y+{VlXgH&iUC*(&b+d%`3b{J~X>#p3)xnzvYhC=%m z2rHH8A@!G1xkfUD6&ke8`BTso4M?*ohW^lz=H~IkF`1-UI@E*?D;RB?_GYA%BNue0 z=_Vp-#;7B_)aWv^)XixN*izI<7Dd_il-ycYA&Mx0-iSU3imS3?xL$V@gG}*`~O)aI%1Y5 z*BKtRpIcc{bg1(4Z8~^ZA)NwBwih0>=T3(<+Fa|0Qrx6}GX3<=hK}$097AuN^nL{| z(DN!u)99cd5Kr%erH6k($4?}6;2PcgXbxyijOO>!iWdVZn2qbWK@zPCv{HG~dlw@C zc$uzlGV%&NV+7#UnyHDpsp0g`=-5N&YQt1K0CAnn+<1nW0SuDP*8-gkuh$I@)QsG! z8TlSvfvWN0J;YY&*7X~@*OJCQdiKz(2ja2cab~SEnJDbx?4RhXiRVZ>ufJc|Lo$Nw z8uNK>Sy6KT44U^pO2JN*X9Z_+hESCZsD Oj3YzK@6+>BuzvvI#l*+} literal 0 HcmV?d00001 diff --git a/target/classes/com/chantha/jdbc/security/User.class b/target/classes/com/chantha/jdbc/security/User.class new file mode 100644 index 0000000000000000000000000000000000000000..6721d646ee80dae1747df63fa32d7d6f25e6ba76 GIT binary patch literal 5629 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 I*2X*k2NCvyV*mgE literal 0 HcmV?d00001 diff --git a/target/classes/com/chantha/jdbc/security/UserDetailServiceImpl.class b/target/classes/com/chantha/jdbc/security/UserDetailServiceImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..6f6a9d1460ff1a7e545bdfd2e08e93fc0ab2126c GIT binary patch literal 2076 zcmbVMTW=dh6#i!8cpc}qH8gQkaMKIaxzJ5QfEJh1q-m*(lU4~tRCyY&C-Kl*fuFz=k060sKtfSokoZx+nYEjwjpZPuo!L1v-<<0==dZti`vbrt))-tbY`9*P z2fE7LTBYo{N_eeE>V5ZXC88Cfx%4+gv@1PPY&3lvjKQh#UGDlk*m0khYr@ku`WWtq z(T=N{kqmaWBi;~uVN^fS=7o`PTcolQt5m1dtB!sf{S5h1S2bEhBGmg$;da0UhKwKb zit%!J-^>BoWO$k{op`sQjW>mRa(uE#2BLYE^h1Lg7{2sPI-r1e^; z*IK?$&>Ou_1mR_05G-Z#ur8XRxzW1-22~isFh&MoVU!_P54A4?x3=4GWk6{OxbGGN z6R47&vT=d*>uMD4tu-kfefg=)A-sjR)5zc=!?p9x*%)US*_J`&bY2&`=C!vra{Lk| z29d>OhMT>y&nN&-HaRiuU54ac8AyGP@}55@K?M`v6-=g)!&QbmUD@+rDsAIBL&8*s zVe&kqgw$2380ODGo_Ro2{>)j1zV@ctthF&sNjoq6m>*M{47a;-yev2obenrRjP_5F z)?I4pa8E{}Qb=K#Vce?`cqwkZJlX#MG`bkPIq#S!9k!5qK$7AawZNxW6-z5x+ zG#veq955Ca7?!)H@VFoLY7-mn4oT4!{=X8s4I-B5!VFo{($28wR$UX~L0F-uJ-ng0 zS6}7LuS{EE7%j;_thE|t5p{MlrO@O4CXb{+bT%)qw*oC2q8RK-C24=@q?J)Wdh_&{ z6R*J>s%JH<93Rq4xYW71*+px5BWy*UcqDy+tJKF56lan~#xypnyG83125A2wN#7C| z3>$LOKf{@M{wI{Al=sM>Jmq`v*g?Z1c^SDQo^;&{3LH z1A}B}2#;wsNmtDJJ-i>E79il2W54ylf#L#1^&_Y;cS%V;2%X+q#Riz{0Xic2~s2 zapSu0chjb?^p*CPblU#V&a{5iGabf1_Fw8u)9>yIJ+Nz->5O*wKF&G!obP_;+^c{6 z=O6zBFpA#^yi{~nv&ALd_LubRa%sMp^^9WKHT{k3o1Woba80{tuIZKvA&^|w*Y&KW z+l$%r^UFrjR}m37;<$@hZ;g_R3$DIuyzRIvH7iBOHL_)zDjB|RT3%pwGHk185@=gA z{E4!^()U-|ixIm=0?_vTeJfoo<9mJug5en}Wh)UoDx(iR=C3@b8bPGN25_sY1 zvMQbvND%W`$1*&*QUWi?u%E}Lh<)Hhu*1{7;p+32q2kl@V8!t*)6N#FXnENhF5X$j z)+4a5Ha%y)W1M#}}Yzz&DOF@If4m;{XnA`5usFYhJ~WfV!l6GsX>iLCCKrFpQBnav0@;b}-zrWxI~q zv^<7aq}<^K-p~1x=PL37CwAtaUg7mdcFtT~vyAP0RB@E3)i4jOpD3GF$#7L1*YK*O zM$_#1!qoK`CP*KBZOyPt0tf364fVz=c@u=uV2aV4#H6$~MO1w!oFvN|BCl9U;B}mq zveN?3K53PJwr4dQLxGs;C3@2!7uJSxiS-Q5$FUC=1lns+o^VJ#-BvNn%~{v2vT=Sv z?(o%m|0_cD{0+RRVGbALXp@GTTuEGk$zA0CPWUrX6_dnB)v>dJf8OWc(%5%h2E(&X!0y<~X4X$NIx zOLT8tRjlP6g*7_55SnFbR~HE!iEYhsvn?k3b_SB%b!KHbpuwp0Q=o5$vQs@AsM2D3 zQ?@J@Btr`Unqx^U(*{$HIlc;878pk$&N+#u&4Z%Wn_({jSJLizP-~y*opg^0xC9cS%U3~wi}9%^r}_L|;AvFMa-zg{y{KU#2#E7Dv~ z?+!7J_g##klU21+0GHQSvnJ0J24H2UZCMRGv*@XKPnN$WqquTGmxmxFrs;Ta9PpH_ zPooMS>NdVYIa&O^j5```<0~4XGV|LDm37bY#4PE)PN<1hT{B2J2!6+D?{Q$YpOY^bSXoTN55}Y zlF>75$)>JYDw3nd(Xs@G0wIGEv?#$vy}+OTC1(LYHLr}nr#a$Uw(8aDy?gq zw;%nXSw>MB78u_}O8<|m1aX1D=q?Ow&j87HdGTQ;G^F{V6&8l*NvA}fwvx`pm2*s7 zNpXQa1=BWW%B%B+TNz1_QMz?ecTFi#8Ely|7n#Flmn!>b$wzb5n6}qV&!o&m?cN}e z**;rkQG-~LG+1&<)k&s`Hs_SxqH)TUeszSMNn^geICaA}$W6xBx1$f%zZ)Ek^{0iG79szhVDfbZ_FoxybRsd{j;i zCbj$My@!EKwB?&3W6kO417rpAYFd4Omj!--S=lp9oxisz9pZCjA;*X?8-yD zO6#wsPTa+*bPHd1apoS*<>LeC_yc@a0q)~czBQdlw?4pS1(!bl1!k?y*5E z-e>;DlJXfb5tLWE7L)~)Kzrl(vB`O`Nx6)l_MX7qh zdSCHkl3(dX*A|0rkUU|O?}Rkk?pLPHV%HP>y15I#dh4vz{Cam6nuAZ&OyO3TbC3~{ z???`$zH}d7?Z1bw^$+|V`~TX2Ofz>_GIMVzTZw~OK^_b82vFq)kvRA@pC(?!`HA2+ zd@J|~eoMj}o;x>jLEB#Xw6np5U+bUi-fErF2D)?Ij|o2g??&~GK;_}?>$Q7}$NH*O z4!7FhhHd{Uu3xX$IO}Wu1ufT;8ytNlpVM+9V`DwT`O(8#Zgk}3p5eif{OA#_f2!tl zPzSaC|I=}~=2%ZIScu>1GWdunE)w3aGrPZW4UuVlGx&WA-`?tdXBywd_c)60UxVlF67`7y5>%-glpZ7$B>GS}iJLgtcq7{z$XkC7 zzkvr-@yL%tjJH4!S}LTq=km@s^Ns!e$Cs}FunJ2AW|~2tHakq34x`;xqe(SyhDw+b z-PK&x_#j9DA@Hf%WkW`NCfjto(dA83ss^e}^*{;PK2WUBKL)BtTg))3@GmV)phk2} zg)N)p*nC#~H(coyN;Qz}(u)!S_dIe6;slESkDh`gfyWn?tqoT^FrxvdC)FZ$?m)=a ztC6KbVv7V;7fzK}H@5lG;#FM{h=-Vg0KE`A;;cJ3!`qvXs}UBE7&1RZ+~s+_y_Pa{8pG0BV=@+eOXr;Rh5jnKQ?G!zq3Qzm6# z@Kk{MR$#V5-$%r_=?G0=?uw=?O?W#0Hys4VtG&SZLefocnC%V^I{l$7!$qwTX<*G5 z0n$TP>j{C%(P1I$OgJaY&19W4+HNj;beL{W932*O`FP%0aiTr8LSDOWynuEw=_XJn zH|D>6PNrrW5|m8pw1&N@_hOS1JKR877ve2!P$fdm$s zvcty*lYuP6Vb0C~z1J{$T|*9Td_emldXwlKNBIaBGI(svqmjTaQN&;YcL(KSBxj>s zJLpNHeG9Q}??J2rZuH%OiQm>_1qv{QUbwplM8iF}zXxdzH#I!a;AxoFkkK#}DKkF- DlqXBC literal 0 HcmV?d00001