搜尋

搜尋結果

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框架會自行把登入者輸入的密碼與加密了的密碼作比較。

永利餐飲學府及安天時酒庫Omtis Fine Wines與瓏岱酒莊合辦大師班
專題報導
小燕品味・2024-01-13

永利餐飲學府及安天時酒庫Omtis Fine Wines與瓏岱酒莊早前於永利澳門合辦一場大師班,酒莊總經理查理middot;特爾特納Charles Treutenaere及酒窖經理梁晨詳細介紹酒莊歷史及理念、葡萄園及風土,以及釀酒技藝,並導引參加者品鑑五款瓏岱及琥岳酒品。 與安天時酒庫(Omtis Fine Wines)董事總經理貝利飛 Philippe Bera, 瓏岱酒莊總經理查理middot;特爾特納Charles Treutenaere及酒窖經理梁晨合影 瓏岱酒莊是拉菲羅斯柴爾德男爵酒業公司在中國的首個計劃,位於山東半島黃海海拔五千米的丘山山谷地區,初心是要釀造一款具有中國特色的混釀葡萄酒。ldquo;瓏rdquo;具有ldquo;琢石成玉rdquo;的寓意,rdquo;岱rdquo;是泰山的古稱,表達對齊魯大地璀璨文化的敬意。 瓏岱酒莊由著名建築師PierreYves Graffe及Barbara Kuckowska等共同設計打造,突顯中華文化的豐富韻味。酒莊主體建築為一座融合古典與現代中式風格的庭院,房頂則是酷似中式傳統的ldquo;重簷歇山頂rdquo;。傳統與現代的結合,中西文化的交融與共用,蘊藏滲透於瓏岱酒莊的各處細節。陳列橡木桶的酒窖則效仿了拉菲集團於1987年在法國拉菲羅斯柴爾德古堡建造的酒窖設計,以紅色為主調,並以道教中的八柱建築風格作為靈感而加入八根紅木廊柱。而酒莊別墅的室內設計,則從中國書法藝術中獲取靈感,精心設計。 圖片來源瓏岱酒莊 圖片來源瓏岱酒莊 圖片來源瓏岱酒莊 回顧瓏岱酒莊的歷史,自2008年在中國多個產區調研,確定選址丘山山谷開始;到2009年探索土壤,2011年種下第一株葡萄樹;經過十年耕耘,終於2019年正式向公眾開放,推出瓏岱干紅葡萄酒2017,至今合共釀造推出了5個年份。2020年,瓏岱酒莊推出了酒莊的另一作品mdash;mdash;琥岳。 圖片來源瓏岱酒莊 瓏岱酒莊位於中國山東省丘山山谷的腹地,總種植面積34公頃,葡萄均採自丘山河谷下木蘭溝村周邊的花崗岩質土壤,分佈在66個田塊的547層梯田,葡萄品種以赤霞珠為主,輔以馬瑟蘭、品麗珠、梅洛、西拉、紫山塞等。園內的一切安排均以實現高精度葡萄栽培為目標。抹芽和綠色採摘可以天然地降低產量,從而有助於葡萄達到出色的多酚成熟度。距離酒莊20公里遠的黃海調節了氣候狀況,溫和的冬季和花崗岩質土壤讓這裡成為葡萄栽培的理想之地。這裡的冬季雖然又乾又冷,但與中國其他很多地區相比又沒有那麼酷寒。夏季高溫,7、8兩月間會有一個短暫的雨季,此後,接連兩個月的乾燥天氣是葡萄成熟的關鍵時期。葡萄園的梯田模式會讓葡萄的成熟時間略有差異,因此,每塊梯田都會經歷多輪採摘,以保證收穫的每串葡萄都達至最佳的成熟狀態。 圖片來源瓏岱酒莊 瓏岱干紅首個年份2017年由赤霞珠、馬瑟蘭和品麗珠混合釀造。赤霞珠和品麗珠等波爾多典型葡萄品種以傳統工藝處理, 精心控制的淋皮工序讓每個酒罐在柔和的手法中完成萃取,從而在圓潤、細膩和悠長之間獲得和諧的平衡度。萃取工序得小心謹慎進行,避免出現乾澀的單寧。 至於更具法國南方特質的葡萄品種,如馬瑟蘭和西拉,在萃取時手法更為柔和,從而有助於讓芳香物質和酚類化合物緩慢擴散。發酵結束的葡萄酒會在拉菲羅斯柴爾德男爵酒業位於波亞克的橡木桶廠出品的橡木桶中分別進行18個月及12月的陳釀。 大師班上品鑑酒莊兩款出品 瓏岱干紅20182020垂直品鑑,由赤霞珠、馬瑟蘭和品麗珠混合釀造,風格宏大濃醇,酒體緊實平衡,單寧結構精緻;琥岳干紅2019及2020年份,混釀了更多葡萄品種,風格以呈現馥郁果香為主,口感圓潤飽滿,結構平衡和諧,是杯醒半個小時便可以愉悅享用的酒款。 當天的品鑑順序分別為 琥岳2020年份由53%赤霞珠、21%品麗珠、12%馬瑟蘭、8%西拉及6%梅洛混釀而成。 琥岳的香氣表現以紅櫻桃和蔓越莓等紅色水果為主,淡淡的甘草等香料香氣則讓酒香更加豐富而有力量, 續後表現出圓潤的口感和細膩的丹寧,回味悠長並伴隨雅致的香草香氣。輕輕搖杯之後,烘烤香氣慢慢顯現,進一步突顯此酒的平衡感。 琥岳2019年份由57%赤霞珠、17%馬瑟蘭、15%西拉及11%品麗珠混釀而成。 琥岳的典型特徵是如紅醋栗和紅櫻桃一般的紅果香氣,隨之而來的還有甘草和白胡椒等香料氣息,展露出既複雜又精緻的芳香風格。入口清爽,結構平衡,口感圓潤飽滿,絲滑的丹寧,悠長的回味,再加上淡淡的可可香氣,充份詮釋此酒的平衡和諧感。 瓏岱2020年份由56%赤霞珠、24%品麗珠、20%馬瑟蘭混釀而成。 瓏岱的香氣是融合了黑色水果如黑醋栗和甘草等香料的複雜氣息。味道豐富,酒體緊實而平衡,丹寧結構精緻。收尾處顯現出烘烤香氣,並帶來舒適圓潤的口感。 瓏岱2019年份由85%赤霞珠、9%品麗珠、6%馬瑟蘭混釀而成。 這款葡萄酒先由黑櫻桃、覆盆子和李子構成的甜美芳香,然後是胡椒香料和雪松的複雜香氣。中度酒體,入口濃醇,結構平衡,顆粒細膩而優雅的丹寧隨之出現,最後一抺黑巧克力的淡淡香氣甜美收尾。 瓏岱2018年份由75%赤霞珠、17%馬瑟蘭及8%品麗珠混釀而成。 這款佳釀首先透露的是藍莓等黑色水果的氣息,接著是肉豆蔻和甘草的香料氣息。醒酒後酒液散發出山楂和紫羅蘭的花香。口感濃郁,以藍莓和黑莓等黑色水果為主,並伴有烘烤和可可的香氣。結構精緻,丹寧濃郁而優雅,回味悠長。 #永利澳門 #永利餐飲學府 #安天時酒庫 #OmtisFineWines #瓏岱酒莊

凱旋門凱旋軒春茗套餐
澳城餐飲
文創遊樂場 // 米米 Esther Lim・2019-11-18

在迎接新春之際,澳門凱旋門凱旋軒為賓客悉心準備多款團年春茗套餐,讓大家共聚一堂,同賀新歲。由主廚精心炮製的佳餚,無論是意頭十足的鴻運琵琶乳豬全體及發財好巿大利、豪氣萬千的蠔皇原隻四頭澳洲鮑魚、新鮮美味的清蒸原條珍珠龍躉及上湯美洲龍蝦伊麵、齒頰留香的生炒臘味糯米飯等,讓賓大家指大動。 團年春茗菜譜由2019年12月15日至2020年2月29日供應,每席由澳門幣4,888起,供十二位用。迎新歲當然少不了品嚐一盆包羅萬有的盆菜。凱旋軒以澳洲鮑魚 六頭、宗谷瑤柱甫、花膠、蠔豉、海蝦等十八款上乘食材炮製出「發財鴻運盆菜」為您送上無限祝福,共迎新春。 「發財鴻運盆菜」由澳門幣988起,由2020年1月1日至23日供應,於2019年12月1日起接受預訂。 細盆菜 $988大盆菜 $1,888 條款及細則: 由2020年1月1日至2020年1月23日供應;所有價格以澳門幣計算,並需收取百分之十服務費;優惠需提前預訂;外賣盆菜需先繳付澳門幣200按金;不可與任何折扣優惠同時使用;受條款及細則約束。 凱旋軒資訊: 營業時間: 上午8時至下午3時;下午6時至晚上11時 訂座電話: 853 8860 6128 地址: 澳門新口岸皇朝區城市日大馬路278號,澳門凱旋門酒店四樓

澳門理工學院設計課程學生作品獲五個國際電影獎項
文化創意
文創遊樂場 // 米米 Esther Lim・2020-02-20

澳門理工學院設澳門理工學院設計課程學生作品計課程學生作品《BLACKBEARS》和《TAKE A RISK》,在最新公佈的紐約電影獎每月電影節(New York Movie Awardsndash;Monthly Festival)、意大利歐尼爾斯電影獎(Oniros Film Awards),以及美國金像國際電影節(American Golden Picture International Film Festival)中,取得優異成績,共獲五個獎項,備受國際電影界的肯定。 兩項獲獎作品,均為紀錄短片。理工學生何家瑋、龍詠詩、蕭承德、李巍的《BLACKBEARS》,榮獲紐約電影獎每月電影節之ldquo;最佳學生電影獎rdquo;,以及歐尼爾斯電影獎之ldquo;最佳運動電影評審團大獎rdquo;。另一組學生吳詠恩、李聲浩、黎詠欣的《TAKE A RISK》,獲得紐約電影獎每月電影節、歐尼爾斯電影獎和美國金像國際電影節共三項榮譽獎。 《BLACKBEARS》講述澳門第一支職業籃球隊ldquo;黑熊rdquo;於2018年6月成立,並參加了東南亞職業籃球聯賽及其他區域性職業賽事。《TAKE A RISK》講述一位出生於澳門的青少年Justin,從籃球明星身上認識了外國傳統的油頭文化(Barber)。他在中學畢業後,全心投入澳門Jokerrsquo;s Barbershop的工作,一步步努力學習,希望未來能夠成為一位優秀的ldquo;Barberrdquo;理髮師。

【澳門甜品】深藏不露!在水坑尾巷子內的高質法式甜品店 — Pâtisserie Racine Du Pin
生活在我城
椒鹽脆餅・2021-03-17

最近這間Racine Du Pin甜品店非常熱門,在蛋糕的設計外型和味道都放了不少心思!甜品店位於水坑尾小巷(信達城對面)!和朋友在水坑尾閒逛一定不能錯過,筆者已多次回訪,每個款式都非常值得一試,因為蛋糕不會太甜,口感豐富! 店內裝潢風格以黑藍色冷調為主,非常有神秘感! Venezuela 店主介紹這個是店內的招牌,甜點外形是可可豆的原形,採用的巧克力成分來自Venezuela single origins,所以直接以產地去命名。外層是佈滿可可粉的慕斯,口感滑順,巧克力味甚濃,非常令人滿足。內層加入紮實的巧克力海棉蛋糕,令口感更豐富。 Choux au chocolat Choux au chocolat 顧名思義就是巧克力泡芙,外皮口感有點像菠蘿包,而裏面忌廉有驚喜,以雙層濃度不一的巧克力作配搭,吃起上來不會太甜而有負擔。 日式卷蛋 卷蛋分別有抹茶和培茶口味,采用日本小山圓的茶粉,茶味香濃,甜中帶苦,甘甜順口,忌廉入口非常厚實有質感,絕不是像空氣般的那種忌廉。兩款都非常可口,但個人感覺抹茶口味更突出。 必食排名推介: Venezuela 必試招牌! Coffee amp; T 雖然沒有很喜歡咖啡類型的甜品,但這個撻質感非常厚實,咖啡味香濃,底層的餅底非常加分! Choux au chocolat 雙重口味忌廉很特別! Pacirc;tisserie Racine Du Pin 地址:澳門柯傳善圍5A(信達城附近) 營業時間:14301900,星期一休息