1. 程式人生 > >springboot整合springsecurity遇到的問題

springboot整合springsecurity遇到的問題

首頁 move close success 分享 沒有 pass ons url

在整合springsecurity時遇到好幾個問題,自動配置登錄,下線,註銷用戶的操作,數據基於mybatis,模版引擎用的thymeleaf+bootstrap。

一、認證時密碼的加密(passwordEncoder)原理如下

  • 其中 MD5Util是自定義密碼加密工具類,隨便寫(註意添加鹽值),註意點:理解匹配密碼這個過程
//認證
    @Override
    protected void configure(AuthenticationManagerBuilder auth)
            throws Exception {
        auth.userDetailsService(userDetailsService()).passwordEncoder(
new PasswordEncoder() { @Override public boolean matches(CharSequence rawPassword, String encodedPassword) { //匹配 =================將用戶表單登錄的密碼和encodedPasswor(這個值是從MyUserDetailService那邊封裝過來的))對比================= return encodedPassword.equals(encode(rawPassword)); } @Override
public String encode(CharSequence rawPassword) { return MD5Util.encode((String) rawPassword); } }); }
  • MyUserDetailService是一個實現了UserDetailsService(springsecurity本身的接口)的方法,在這裏面實現認證的數據查詢及其登錄用戶權限查詢封裝。
  • 註意點:理解權限的賦予,即當前用戶在這裏就已經將所有的角色封裝到springsecurity本身的User中了,但是在這裏並沒有認證成功,單純的進行封裝而已
技術分享圖片
@Service
public class MyUserDetailService implements UserDetailsService {

    @Autowired
    UserService userService;
    @Autowired
    private SessionRegistry sessionRegistry;
    
    @Override
    public UserDetails loadUserByUsername(String username)  {
        
        if (username==null || username.equals("")) {
             throw new UsernameNotFoundException("用戶名不存在");
        }
        
        Sys_User user=userService.getUserByName(username);
        
         //獲得所有登錄用戶的信息
         List<Object> list =sessionRegistry.getAllPrincipals();
         for (Object object : list) {
             if (((User)object).getUsername().equals(user.getUsername())) {
                 throw new SessionAuthenticationException("當前用戶已經在線,登錄失敗");
             }
             System.out.println("getAllPrincipals的遍歷"+((User)object).getUsername());
         }
        
        //得到當前登錄用戶的信息
         List<SimpleGrantedAuthority> authorities = new ArrayList<>();
         
         for (Role role : user.getRoles()) {
             //將得到的角色封裝  在後面頁面認證成功後會用到
               authorities.add(new SimpleGrantedAuthority(role.getRolename()));
               System.out.println("擁有的角色:"+role.getRolename());
            }
        return  new User(user.getUsername(), user.getPassword(), authorities);
    }

}
View Code

二、授權時session的管理的配置(configure(HttpSecurity http)中)

  • 這個可以說是核心了,首先開啟自動配置的註銷功能(重點在開啟否則默認的是自帶的註銷頁面),LogoutUrl:自定義的登出URL,登出成功後的頁面也可以自定義,這裏就都不寫了,在controller層實現自己定義的
//開啟自動配置的註銷功能。
        http.logout().permitAll();//logoutUrl("/logout").logoutSuccessUrl("/");//表示註銷成功以後來到首頁
        http //session管理
        .sessionManagement()
        .maximumSessions(1).maxSessionsPreventsLogin(true)
        .sessionRegistry(getSessionRegistry());
  • http.sessionManagement().invalidSessionUrl("/login") 使用未過期但完全無效的sessionid用戶發送請求,也會被重定向至特定url
 http.sessionManagement().maximumSessions(1).maxSessionsPreventsLogin(true)
  • MaximumLogins必須是-1以允許無限制的登錄,或者是一個正整數來指定最大值
  • .maximumSessions(1)設置一個用戶允許登錄的個數 maxSessionsPreventsLogin 啟用超出報錯。

    在實測後發現設定上限後 最大登錄次數為設定數目 +1 比如設定數2 則最大訪問數目為3 第四次開始報錯
    由此 如果我們用這個配置去指定用戶單登錄是不行的

  • http.sessionManagement().sessionFixation().migrateSession()spring security防止篡改session

三、自定義註銷,下線的實現(重點)

  • 第一種實現單純的進行了下線,暫時將session置為無效,並未去掉(看源碼部分)
if (invalidateHttpSession) {//部分源碼
            HttpSession session = request.getSession(false);
            if (session != null) {
                logger.debug("Invalidating session: " + session.getId());
                session.invalidate();
            }
        }

 @RequestMapping("/logout")
    public String logout(HttpServletRequest request,HttpServletResponse response){
        /**
         * 第一種方式  單純的離線  並未註銷用戶   即sessionID還在
         * 
         */
        
        //獲得註銷用戶的信息
        Authentication auth=SecurityContextHolder.getContext().getAuthentication();
        if (auth != null){
            //設置為離線狀態
           new SecurityContextLogoutHandler().logout(request, response, auth);
        }
        return "redirect:/login";
        
    }
  • 第二種徹底將sessionid從sessionRegistry中移除,實現用戶註銷
@RequestMapping("/logout")
    public  String  logout2() {
          
        /**
         * 第二種  將獲取到登錄用戶信息後將該用戶sessionID置為無效   然後再從sessionRegistry中移除
         * 這種方式可以徹底註銷用戶登錄狀態
         */
        
    List<Object> pList=sessionRegistry.getAllPrincipals();
    List<SessionInformation>  sessionsInfo = null;
    for (Object principle : pList) {
        sessionsInfo=sessionRegistry.getAllSessions(principle, false);
    }
         System.out.println("sesssion個數"+sessionsInfo.size());
         for (SessionInformation sessionInformation : sessionsInfo) {
             //獲取當前sessionid
             System.out.println("SESSIONID:"+sessionInformation.getSessionId());
             sessionInformation.expireNow();//將session置為無效然後在下一步移除
             sessionRegistry.removeSessionInformation(sessionInformation.getSessionId());
        }
        return "redirect:/login";
    }
    

四、源碼

源碼實現私信我

springboot整合springsecurity遇到的問題