SpringSecurity

 安全访问控制解决方案的安全框架   登录控制

SpringSecurity https://www.cnblogs.com/qiantao/p/14605154.html
登录 http://localhost:9091/user/login form表单提交 username password   没有登录,请求会跳转到登录页面  密码错误,跳转失败页面

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
            <version>2.6.4</version>
        </dependency>
        <dependency><!--json-->
            <groupId>org.nutz</groupId>
            <artifactId>nutz</artifactId>
            <version>1.r.62</version>
        </dependency>

/**
 * ringSecurity安全框架配置
 */
@Configuration
@EnableWebSecurity//开启Spring Security的功能
//prePostEnabled属性决定Spring Security在接口前注解是否可用@PreAuthorize,@PostAuthorize等注解,设置为true,会拦截加了这些注解的接口
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class WebSecurityConfg extends WebSecurityConfigurerAdapter {
    @Resource
    private AuthenticationSuccessHandler loginSuccessHandler; //认证成功结果处理器
    @Resource
    private AuthenticationFailureHandler loginFailureHandler; //认证失败结果处理器

    //http请求拦截配置
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.headers().frameOptions().disable();//开启运行iframe嵌套页面

        http//1、配置权限认证
                .authorizeRequests()
                //配置不拦截路由
                .antMatchers("/500").permitAll()
                .antMatchers("/403").permitAll()
                .antMatchers("/404").permitAll()
                .antMatchers("/login").permitAll()
                .anyRequest() //任何其它请求
                .authenticated() //都需要身份认证
                .and()
                //2、登录配置表单认证方式
                .formLogin()
                .loginPage("http://www.baidu.com")//自定义登录页面的url /login
                .usernameParameter("username")//设置登录账号参数,与表单参数一致
                .passwordParameter("password")//设置登录密码参数,与表单参数一致
                // 告诉Spring Security在发送指定路径时处理提交的凭证,默认情况下,将用户重定向回用户来自的页面。登录表单form中action的地址,也就是处理认证请求的路径,
                // 只要保持表单中action和HttpSecurity里配置的loginProcessingUrl一致就可以了,也不用自己去处理,它不会将请求传递给Spring MVC和您的控制器,所以我们就不需要自己再去写一个/user/login的控制器接口了
                .loginProcessingUrl("/user/login")//配置默认登录入口
                .defaultSuccessUrl("/index")//登录成功后默认的跳转页面路径
                .failureUrl("/login?error=true")
                .successHandler(loginSuccessHandler)//使用自定义的成功结果处理器
                .failureHandler(loginFailureHandler)//使用自定义失败的结果处理器
                .and()
                //3、注销
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessHandler(new CustomLogoutSuccessHandler())
                .permitAll()
                .and()
                //4、session管理
                .sessionManagement()
                .invalidSessionUrl("/login") //失效后跳转到登陆页面
                //单用户登录,如果有一个登录了,同一个用户在其他地方登录将前一个剔除下线
                //.maximumSessions(1).expiredSessionStrategy(expiredSessionStrategy())
                //单用户登录,如果有一个登录了,同一个用户在其他地方不能登录
                //.maximumSessions(1).maxSessionsPreventsLogin(true) ;
                .and()
                //5、禁用跨站csrf攻击防御
                .csrf()
                .disable();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        //配置静态文件不需要认证
        web.ignoring().antMatchers("/static/**");
    }
    /**
     * 指定加密方式
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        // 使用BCrypt加密密码
        return new BCryptPasswordEncoder();
    }



@Component
public class CustomUserDetailsService implements UserDetailsService {
    @Resource
    private PasswordEncoder passwordEncoder;
    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        /**
         * 1/通过userName 获取到userInfo信息
         * 2/通过User(UserDetails)返回details。
         */
        //通过userName获取用户信息
//        UserInfo userInfo = userInfoService.getUserInfoByUsername(userName);
        UserInfo userInfo = new UserInfo("xmh","123","admin");
        if(userInfo == null) {
            throw new UsernameNotFoundException("not found");
        }
        //定义权限列表.
        List<GrantedAuthority> authorities = new ArrayList<>();
        // 用户可以访问的资源名称(或者说用户所拥有的权限) 注意:必须"ROLE_"开头
        authorities.add(new SimpleGrantedAuthority("ROLE_"+ userInfo.getRole()));
        User userDetails = new User(userInfo.getUserName(),passwordEncoder.encode(userInfo.getPassword()),authorities);
        return userDetails;
    }
}


/**
 * @Description 登录成功处理
 */
@Component("loginSuccessHandler")
public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {

    @Resource
    private ObjectMapper objectMapper;

    private RequestCache requestCache;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
        // 获取前端传到后端的全部参数
          Enumeration enu = request.getParameterNames();
          while (enu.hasMoreElements()) {
              String paraName = (String) enu.nextElement(); System.out.println("参数- " + paraName + " : " + request.getParameter(paraName));
          }
        logger.info("登录认证成功");
        //这里写你登录成功后的逻辑,可以验证其他信息,如验证码等。
        response.setContentType("application/json;charset=UTF-8");
        Map resultObj = new HashMap<>();
        resultObj.put("code", HttpStatus.OK.value());
        resultObj.put("msg","登录成功");
        resultObj.put("authentication",objectMapper.writeValueAsString(authentication));
        response.getWriter().write(Json.toJson(resultObj));
//        this.getRedirectStrategy().sendRedirect(request, response, "/index");//重定向
    }
}

/**
 * @Description 登录失败处理
 */
@Component("loginFailureHandler")
public class LoginFailureHandler extends SimpleUrlAuthenticationFailureHandler {
    @Resource
    private ObjectMapper objectMapper;

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        logger.info("登录失败");
        this.saveException(request, exception);
        //this.getRedirectStrategy().sendRedirect(request, response, "/login?error=true");
        response.setContentType("application/json;charset=UTF-8");
        Map resultObj = new HashMap<>();
        resultObj.put("code", "01");
        resultObj.put("msg","login fail 失败");
        response.getWriter().write(Json.toJson(resultObj));
    }
}

public class CustomLogoutSuccessHandler implements LogoutSuccessHandler {
    @Override
    public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        System.out.println("注销成功!");
        //这里写你登录成功后的逻辑
        response.setStatus(HttpStatus.OK.value());
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write("注销成功!");
    }
}

    @GetMapping("/hello")
    @ResponseBody
    public String hello() {
        System.out.println("*****hello****");
        return "hello";
    }

  

 

posted @ 2023-03-21 13:50  XUMT111  阅读(25)  评论(0)    收藏  举报