Springboot+Vue實現線上聊天室專案-整合springSecurity配置實現登入的許可權控制
阿新 • • 發佈:2020-12-19
Springboot+Vue實現線上聊天室專案目錄
該聊天室為大二上學期計算機網路大作業,並且是本人第一次使用vue實現前後端分離的專案,前端架構尚未熟悉可能會出現一些不妥之處,還請大佬們指出。(本文章寫於專案整體完成上線之後,所以一些細節並未寫出)
pom匯入springSecurity
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
編寫配置檔案
在config資料夾中建立註解為
@Configuration
@EnableWebSecurity
並繼承WebSecurityConfigurerAdapter的配置類
其中依賴注入UserService用於密碼檢測,corsFilter用於跨域配置
配置http的security
其中,.sessionManagement().invalidSessionUrl("/session/invalid").用於登入許可權過期時的跳轉,當sesion中的資訊過期時,前端再次訪問會跳轉到session/invalid介面。這裡在前端加一個攔截器檢測該介面的返回,如果出現則前端跳轉到登入頁面
這裡配置/register、/invalid兩個介面不受許可權控制,為permitAll。formLogin也為permitAll,即登入、註冊、過期三個介面不受許可權限制。
配置http登入成功、失敗、登出
.successHandler(new AuthenticationSuccessHandler() { @Override public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException { System.out.println("登陸成功"); Map<String, Object> map = new HashMap<>(); map.put("msg", "登入成功!"); map.put("principal", authentication.getPrincipal()); resp.setContentType("application/json;charset=utf-8"); resp.setHeader("Access-Control-Allow-Origin","http://www.guoruijava.xyz"); resp.setHeader("Access-Control-Allow-Credentials", "true"); resp.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT"); resp.setHeader("Access-Control-Max-Age", "3600"); resp.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); PrintWriter out = resp.getWriter(); // 物件轉json傳輸給前端 out.write(new ObjectMapper().writeValueAsString(map)); out.flush(); out.close(); } }) .failureHandler(new AuthenticationFailureHandler() { @Override public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp, AuthenticationException e) throws IOException, ServletException { System.out.println("登入失敗"); Map<String, Object> map = new HashMap<>(); resp.setContentType("application/json;charset=utf-8"); resp.setHeader("Access-Control-Allow-Origin", "http://www.guoruijava.xyz"); resp.setHeader("Access-Control-Allow-Credentials", "true"); resp.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH"); resp.setHeader("Access-Control-Max-Age", "3600"); resp.addHeader("Access-Control-Allow-Headers", "token,accesstoken,Content-type"); System.out.println("設定resp" + resp.toString()); PrintWriter out = resp.getWriter(); if (e instanceof BadCredentialsException){ map.put("msg","賬號或密碼輸入錯誤,登入失敗!"); }else{ map.put("msg","出現異常,登入失敗!"); } // 物件轉json傳輸給前端 out.write(new ObjectMapper().writeValueAsString(map)); out.flush(); out.close(); } }) .permitAll() .and() .logout() .logoutUrl("/logout") .permitAll() .logoutSuccessHandler(new LogoutSuccessHandler() { @Override public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException { Map<String, Object> map = new HashMap<>(); map.put("state", 200); map.put("msg", "登出成功!"); resp.setContentType("application/json;charset=utf-8"); resp.setHeader("Access-Control-Allow-Origin","http://www.guoruijava.xyz"); resp.setHeader("Access-Control-Allow-Credentials", "true"); resp.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT"); resp.setHeader("Access-Control-Max-Age", "3600"); resp.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); PrintWriter out = resp.getWriter(); // 物件轉json傳輸給前端 out.write(new ObjectMapper().writeValueAsString(map)); out.flush(); out.close(); } }) .permitAll();
配置資料庫的security許可權
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
System.out.println("許可權管理");
auth.userDetailsService(userService);
}
security的攔截器會呼叫這裡userService中的loadUserByUsername方法,這個方法是實現UserDetailsService介面重寫的方法
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
User use = userDao.getUserByAccount(s);
if (use == null){
throw new UsernameNotFoundException("使用者名稱不存在");
}else{
System.out.println(new User(use.getId(),use.getName(),use.getImg(),use.getAccount(),use.getPassword(),"ROLE_USER",
userDao.getMyFriends(use.getFriends().split("\\|")),userDao.getMyRooms(use.getRooms().split("\\|"))).toString());
return new User(use.getId(),use.getName(),use.getImg(),use.getAccount(),use.getPassword(),"ROLE_USER",
userDao.getMyFriends(use.getFriends().split("\\|")),userDao.getMyRooms(use.getRooms().split("\\|")));
}
}
登入成功後,由security將使用者資訊principal存入容器中,這個資訊可以通過SecurityContextHolder.getContext().getAuthentication().getPrincipal()來獲取(用於後續使用者操作時獲取使用者的資訊許可權)
。這裡將獲取使用者id作為靜態方法放在UserService中
public static int getUserIdCurrent(){
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
int id = ((User)principal).getId();
return id;
}