標籤:資訊 handler val 注意 null lin out 源碼 功能
在整合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中了,但是在這裡並沒有認證成功,單純的進行封裝而已
@Servicepublic 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)
三、自訂登出,下線的實現(重點)
- 第一種實現單純的進行了下線,暫時將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遇到的問題