zoukankan      html  css  js  c++  java
  • springboot整合springsecurity遇到的问题

    在整合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";
        }
        
  • 相关阅读:
    [POI2000]病毒
    枪战(maf)
    禅与园林艺术(garden)
    The Cave
    集合选数
    BZOJ3990 排序(sort)
    区间(interval)
    太空飞船(spaceship)
    数表( table )
    Printed Circuit Board (board)
  • 原文地址:https://www.cnblogs.com/renjiaqi/p/11495890.html
Copyright © 2011-2022 走看看