搜尋

搜尋結果

Spring Boot 05 - 為 http json api 加入登入要求
科技新知
MacauYeah・2024-07-02

本節,我們將為之前的http服務,加入認證機制,只有在資料庫現存的用戶可以登入及訪問我們的json api。 下戴模版 慣例,我們用Spring Initializr Maven 下載模版,Dependency主要選擇 Spring Web Spring Boot DevTools Spring Security Controller 跟上節一樣,我們起一個Controller,為簡化測試,我們只做http GET api。 由於本blog對於Source Code的顯示不太友好,有需要看source code的,請到Github查看 srcmainjavaiogithubmacauyeahspringboottutorialspringbootwebapidatacontrollerHomeController.java import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMappingquot;apiquot; public class HomeController @GetMappingquot;someRecorduuidquot; public Map readSomeRecord@PathVariable String uuid return Map.ofquot;retquot;, quot;your uuidquot; uuid; 準備我們的test case,但這次我們預期它應該要出現登入失敗的結果。 srctestjavaiogithubmacauyeahspringboottutorialspringbootwebapidatacontrollerHomeControllerTest.java @SpringBootTest @AutoConfigureMockMvc public class HomeControllerTest @Autowired private MockMvc mockMvc; @Test void testNoLogin throws Exception RequestBuilder requestBuilder = MockMvcRequestBuilders.getquot;apisomeRecord1234quot; .contentTypeMediaType.APPLICATION_JSON; this.mockMvc.performrequestBuilder .andExpectMockMvcResultMatchers.status.is4xxClientError .andExpectMockMvcResultMatchers.jsonPathquot;$.retquot;.doesNotExist .andDoMockMvcResultHandlers.print; 在我們執行上述的測試,test case 成功過了。我們的基本設定跟上一節其實沒有多大改動,為何現在http api會回傳狀態 401? 那是因為我們在依賴中加了,Spring Security,它配合了Spring Web,就會自動為所有api加入權限檢測。我們的測試中,沒有任何用戶登入,當然會出現 http 401。為了讓我們可以好好管理誰可以使用api,我們就來設定一定Security。 我們加一個WebSecurityConfig.java,暫時指定所有的訪問路徑都必需有USER權限,並且用 http basic的方式登入。 srcmainjavaiogithubmacauyeahspringboottutorialspringbootwebapidataconfigWebSecurityConfig.java import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.web.SecurityFilterChain; @Configuration @EnableWebSecurity public class WebSecurityConfig @Bean SecurityFilterChain securityFilterChainHttpSecurity http throws Exception http.authorizeHttpRequestsauthorizeHttpRequests gt; authorizeHttpRequests.requestMatchersquot;quot;.hasRolequot;USERquot;; 所有的訪問路徑都必需有USER權限 ; http.httpBasicCustomizer.withDefaults; 使用http basic作為登入認證的方式 return http.build; 上述例子,只是擋了沒有權限的人,我們還需要讓有登入身份的用戶可以成得取限User權限。 我們繼續修改,WebSecurityConfig,加入只在記憶體有效的InMemoryUser 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.provisioning.InMemoryUserDetailsManager; public class WebSecurityConfig .. @Bean public PasswordEncoder passwordEncoder return new BCryptPasswordEncoder; 我們的密碼不應該明文儲,比較保險,我們使用BCrypt演算法,為密碼做單向加密。 @Bean public UserDetailsService userDetailsService UserDetails user = User.withUsernamequot;adminquot; .passwordpasswordEncoder.encodequot;passquot; .rolesquot;USERquot;.build; 我們在記憶中體,加入一個測試用的User,它的名字為admin,密碼為pass,權限為User return new InMemoryUserDetailsManageruser; 然後加入新的測試,直接模擬Role。結果是通過的。 srctestjavaiogithubmacauyeahspringboottutorialspringbootwebapidatacontrollerHomeControllerTest.java @Test void testLoginWithRoles throws Exception RequestBuilder requestBuilder = MockMvcRequestBuilders.getquot;apisomeRecord1234quot; .contentTypeMediaType.APPLICATION_JSON.with SecurityMockMvcRequestPostProcessors.userquot;someonequot; .rolesquot;USERquot;, quot;ADMINquot;; 沒有使用密碼,只使用Role this.mockMvc.performrequestBuilder .andExpectMockMvcResultMatchers.status.is2xxSuccessful .andExpectMockMvcResultMatchers.jsonPathquot;$.retquot;.valuequot;your uuid1234quot; .andDoMockMvcResultHandlers.print; 再來一個測試,改用密碼登入,分別輸入錯的和正確的密碼。 @Test void testLoginWithWrongPasswordAndNoRole throws Exception RequestBuilder requestBuilder = MockMvcRequestBuilders.getquot;apisomeRecord1234quot; .headerquot;Authorizationquot;, quot;Basic randompassquot; 輸入錯的密碼,應該回傳http 401 Unauthorized .contentTypeMediaType.APPLICATION_JSON; this.mockMvc.performrequestBuilder .andExpectMockMvcResultMatchers.status.is4xxClientError .andDoMockMvcResultHandlers.print; @Test void testLoginWithPassword throws Exception RequestBuilder requestBuilder = MockMvcRequestBuilders.getquot;apisomeRecord1234quot; .headerquot;Authorizationquot;, quot;Basic YWRtaW46cGFzcw==quot; http basic 就是把 adminpass 轉成base64 .contentTypeMediaType.APPLICATION_JSON; this.mockMvc.performrequestBuilder .andExpectMockMvcResultMatchers.status.is2xxSuccessful .andExpectMockMvcResultMatchers.jsonPathquot;$.retquot;.valuequot;your uuid1234quot; .andDoMockMvcResultHandlers.print; 最後,當然是正確的密碼才能通過。若果大家還是半信半疑,我們可以跑起真的正服務(IDE RUN或mvn springbootrun),然後用curl去試。 curl httplocalhost8080apisomeRecord1234 failed with 401 curl u quot;adminpassquot; httplocalhost8080apisomeRecord1234 successed 使用SQL Database讀取用戶登入資訊 一般而言,我們不可能把所有用戶登資訊打在InMemoryUser中,通常背後有一個資料庫儲存所有的用戶資訊,我們在登入時,讀取它來做對比檢證。 為此,我們在maven中,加入 Spring Data JPA h2 database (或任何你的資料庫,如mysql 、 sql server) 最後一步,我們把InMemoryUser去掉,改為從資料庫讀取。因為原始碼太多,就不全部貼上。最主要的是WebSecurityConfig.java要關掉之前的UserDetailsService,改為提供一個UserServiceImpl類,它會實現UserDetailsService的功能。 @Configuration @EnableWebSecurity public class WebSecurityConfig 把原來的Bean先變成註解,其他不變 @Bean public UserDetailsService userDetailsService UserDetails user = User.withUsernamequot;adminquot; .passwordpasswordEncoder.encodequot;passquot; .rolesquot;USERquot;.build; return new InMemoryUserDetailsManageruser; springboottutorialspringbootwebapidatasrcmainjavaiogithubmacauyeahspringboottutorialspringbootwebapidataconfigUserServiceImpl.java other import import org.springframework.security.core.authority.SimpleGrantedAuthority; 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.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; @Service public class UserServiceImpl implements UserDetailsService @Autowired PasswordEncoder passwordEncoder; @Autowired UserRepo userRepo; @Override public UserDetails loadUserByUsernameString username throws UsernameNotFoundException 因為我們資料庫沒有資料,為了方便測試密碼的加密,我們在java code上直接插入一筆資料。 UserEntity defaultUser = new UserEntity; defaultUser.setUsernamequot;adminquot;; defaultUser.setPasswordpasswordEncoder.encodequot;passquot;; defaultUser.setRolequot;USERquot;; defaultUser.setUuidUUID.randomUUID.toString; userRepo.savedefaultUser; 上述為測試用插入資料,不應該出現在正式使用環境中。 UserEntity user = userRepo.findOneByUsernameusername .orElseThrow gt; new UsernameNotFoundExceptionusername quot; not foundquot;; 找找資料庫有沒有正在登入的該名使用者username List authorities = List.ofnew SimpleGrantedAuthorityquot;ROLE_quot; user.getRole; LOG.debugquot;got user uuid, username, role from databasequot;, user.getUuid, username, user.getRole; 如果前面的 findOneByUsername 有結果回傳,我們就給它一個ROLE_XXX的權限。 return new Userusername, user.getPassword, authorities; 這裏從沒有檢查過密碼是否有匹配,全部交給Spring Security去做 springboottutorialspringbootwebapidatasrcmainjavaiogithubmacauyeahspringboottutorialspringbootwebapidataentityUserEntity.java springboottutorialspringbootwebapidatasrcmainjavaiogithubmacauyeahspringboottutorialspringbootwebapidatarepoUserRepo.java 上述段落中,筆者省略了UserEntity和UserRepo,它們只是一般的springdatajpa概念,有需要可以經文末的連結查看完全原始碼。最需要注意的,是UserEntity的password欄位,在資料庫中是以加密的方式儲存。我們在配匹登入者與資料庫記錄時,也沒有自行檢驗密碼的需要。我們只是在加密過的密碼回傳給Spring Security,Spring框架會自行把登入者輸入的密碼與加密了的密碼作比較。

『足球王國西班牙』3分鐘看透三大主球場
走遍世界
行走世界記錄・2019-03-12

歐洲大陸有一座比利牛斯山脈, 山脈西端的伊比利亞半島上, 有著一個為人熟悉的國家。 這個曾經與葡萄牙人競賽, 開展西方航海的新時代的國家, 建立起叱咤一時的日不落帝國。 西班牙 熱情與浪漫, 勇敢與奔放, 是西班牙民族的標誌。 在這片熱情奔放的土地上 有著舉世聞名的足球隊伍 足球王國 作為足球王國的西班牙,全國各大城市都擁有各自的足球隊,皇家馬德裏 (Real Madrid、馬德裏競技(Atleacute;tico de Madrid、巴塞隆納(Barccedil;a,都是為人熟悉的名字。 這三支勁旅各自有專屬的主球場,除了觀賞球賽外,亦開放給球迷購票入內參觀。往下看便是本篇的重點,3分鐘帶大家遊遍3大主球場,請落足眼力呢! 皇家馬德里 (Real Madrid 皇家馬德里的主場 聖地亞哥middot;伯納烏球場 皇家馬德里足球俱樂部成立於1902年 聖地亞哥middot;伯納烏球場於1947年12月14日落成 以已故球會主席Santiago Bernabeu命名 球場容納85,454人 球員更衣室 儲物櫃挔球員號碼排列,也包括休息室,浴室和健身室。 新聞發布會廳 皇馬這個是可以坐上去拍照的 嘩樂透了 教練席 哇這個也可任意上座的 巴塞隆納(Barccedil;a 巴賽隆納的主場 諾坎普體育場 1899年由瑞士企業家創立球會 1957年9月24日正式啟用 全歐洲最大的球場 容納10萬名觀眾 評述員席 進入球場上層的足球評述員位置,居高臨下呢 新聞發布會廳 巴塞這個是不可以坐上去的啊 球員更衣室 跟皇馬的相比,巴塞的更衣室更為簡潔。 小教堂 在球員通道旁有一個給球員祈禱用的小教堂,真的很貼心。 馬德里競技(Atleacute;tico de Madrid 馬德里競技的主場 比森特middot;卡爾德隆球場 比森特middot;卡爾德隆球場於1966年落成 容納 57,000 名觀眾 2016年使用新球場 萬方球場 已成歷史的球場 讓舊球場給大家作紀念! 『足球王國西班牙』 來到西班牙,除了看鬥牛吃火腿,觀賞弗拉明戈舞蹈,還有一個指定的旅遊動作 參觀足球場。不論你是否球迷,想必正在翻手機爬文的您,看過本篇後,也會有一刻心動,立馬來個團體或自助遊吧! 更多精彩文章在行走世界記錄

澳門康萊德以高尚格調及豐富美饌歡賀猴年
澳城餐飲
LifeMag Editor・2016-01-22

爆竹一聲除舊歲,火樹銀花迎新年。踏入丙申猴年又是另一新氣象,為慶祝賀新春佳節,屢獲殊榮的澳門金沙城中心康萊德酒店將於農曆新年期間推出多款令人垂涎欲滴的佳餚及賀年套餐。不論是與親朋摯友一同享受高雅的晚餐、舒適地邊暢談邊享用豐富的下午茶、享用包羅萬有的自助餐,又或是在豪華及私密度十足的澳門康萊德酒店套房內享用美饌等,此五星級酒店皆應有盡有。 此外,凡於2月8日起入住澳門康萊德酒店的賓客,可獲贈2016年動物印花系列的獨家限量版長頸鹿印花康萊德春節小熊及幸運鴨子。同時,這兩款限量珍藏品亦於2月7日起在禮品軒獨家發售。如欲預訂於春節期間入住澳門康萊德酒店,可瀏覽www.conradmacao.com、致電853 8113 6000,或電郵macao.reservations@conradhotels.com。 在餐飲方面,「朝」、「奧旋自助餐」及大堂酒廊將為賓客提供一系列誘人美食以迎接農曆新年的來臨。酒店的旗艦高級中菜餐廳「朝」特設了色香味俱全的應節套餐、「奧旋自助餐」準備了滋味豐足的自助餐、大堂酒廊則備好了傳統下午茶自助餐;所有您於佳節期間期望的啟發體驗,均可在澳門康萊德酒店裡獲得。 酒店營運副總裁畢貝禮表示:「我們很高興能於澳門康萊德酒店為賓客提供各式各樣的新春佳餚,以迎接猴年的來臨。新年伊始,是與家人及朋友歡聚慶祝的好時光,我們依然謹記我們客人多樣化的需求和品味,並致力超越他們的期望及為他們帶來驚喜。」 「朝」 由2月7日至14日,澳門康萊德的「朝」將呈獻一系列八道或九道佳餚的新春午膳菜單,及八道或十道佳餚的新春晚膳菜單,精選傳統菜式包括好市添發財﹝蠔豉髮菜瑤柱脯﹞、包羅萬千有 ﹝鮑魚螺頭燉雞湯﹞、連年有盈餘﹝清蒸海杉斑﹞以及花開添富貴 ﹝鮮蟹肉西蘭花﹞ 等。 屢獲殊榮的「朝」餐廳位於金沙城中心地面樓層,營業時間為星期一至五上午11時至下午3時及下午6時至晚上11時(星期六及日於早上10時營業)。於農曆新年期間,營業時間將延長,2月7日為上午11時至下午3時及下午6時至午夜12時;2月8日至13日為上午10時至下午3時及下午6時至午夜12時;2月14日為上午10時至下午3時及下午6時至晚上11時;可供四人享用的午膳套餐價格為澳門幣1,888元起及晚膳套餐價格為澳門幣2,888元起。預約請致電853 8113 8920或電郵macau.dynasty8.reservation@conradhotels.com。 此外,於1月25日至2月14日期間,渴望一嚐傳統盆菜滋味的賓客萬勿錯過「朝」推出的傳統盆菜,與摯愛親朋一同在家中分享佳節滋味。可供四人份的外賣盆菜包括蝦、鮑魚、金蠔、魚肚、燒鴨等,價格為澳門幣1,888元。 預訂請致電853 8113 8920。 「奧旋自助餐」 「奧旋自助餐」將於2月7日至14日期間供應滋味豐足的農曆新年自助餐,包括地中海、西式、中式、日式、葡萄牙、東南亞及印度等特色菜餚,並提供豐富的冰鮮海產。「奧旋自助餐」位於金沙城中心地面樓層,自助午餐於每天中午12時至下午3時供應,而自助晚餐分別於每天下午5時30分至晚上8時及晚上8時30分至11時供應。自助午餐價格為澳門幣298元(成人)及澳門幣149元(小童);而自助晚餐價格為澳門幣468元(成人)及澳門幣234元(小童),預約請致電853 8113 8910。 大堂酒廊 大堂酒廊將於2月6日至13日期間特別供應「大堂酒廊農曆新年下午茶套餐」以慶祝新春佳節,精選多款美味小食及別緻的傳統咸點和甜點,包括蒸蝦餃、番茄包和蟹肉沙拉配薑絲、香辣雞翅膀、軟包配烤豬肉、荔枝洛神花泡芙、蛋撻、紅色絲絨巧克力蛋糕、蜂蜜橘子烤松餅及農曆新年特製的幸運無酒精雞尾酒或雞尾酒。尊貴下午茶套餐價格為澳門幣258元;而豪華下午茶套餐價格為澳門幣298元,包括康萊德獨家春節小熊或幸運鴨子一隻。大堂酒廊位於康萊德酒店大堂,下午茶供應時間為每天下午3時至6時,預約可致電853 8113 8970。 如欲了解澳門康萊德酒店於春節期間的各項最新資訊,請瀏覽澳門金沙城中心康萊德酒店網站、亦可瀏覽Facebook專頁facebook.comconradmacao或Instagram專頁instagram.comconradmacao 。