Springboot+Vue實現線上聊天室專案-整合springSecurity配置實現登入的許可權控制

Guriii發表於2020-12-18

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;
    }

相關文章