spring security :ajax登录,用countroller控制返回json数据

spring security :ajax登录


这一篇文章便不是具体的教程,只会说我这个登录涉及到的相关东西。

WebSecurityConfigurerAdapter的实现类:

值得注意的是,userService应该是实现了UserDetailsService接口。setHideUserNotFoundExceptions(false)这个设置为false的话,可以返回UserNotFoundException,从而可以区分是用户名还是密码有问题。

值得注意的是,failureForwardUrl和failureUrl的区别是前者访问的是 /user/login/failure 的@PostMapping请求,而后者访问的则是@GetMapping请求。

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        // 设置不隐藏 未找到用户异常
        provider.setHideUserNotFoundExceptions(false);
        // 用户认证service - 查询数据库的逻辑
        provider.setUserDetailsService(userService);
        // 设置密码加密算法
        provider.setPasswordEncoder(passwordEncoder());

        auth.authenticationProvider(provider);
    }
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            //用于配置直接放行的请求
            .antMatchers("/user/login/failure","/login").permitAll()
            //其余请求都需要验证
            .anyRequest().authenticated()
            .and().formLogin()
            	//自定登录页面
	            .loginPage("/login")
	            //登录处理url,在ajax post请求/base/user/login会被这里捕获
                .loginProcessingUrl("/user/login")
                //登录成功会跳到controller的这个地址
                .successForwardUrl("/user/login/success")
                //登录失败会跳到controller的这个地址
                .failureForwardUrl("/user/login/failure")
                //也可以用failureUrl,登录失败会跳到controller的这个地址
                //.failureUrl("/user/login/failure")
            //禁用跨站伪造
            .and().csrf().disable();

    }

UserController.java中捕获返回,这里直接返回String,可以改成返回JSON对象
值得注意的是,如果用的是failureForwardUrl,则exception 是存到request中的,而用的是failureUrl的话,则exception 是存到session中的。
推荐是用failureForwardUrl喽,session干净点,心情好一点。

   @GetMapping("/user/login/failure")
    @ResponseBody
    public Stringfailure1(HttpServletRequest request){
        AuthenticationException exception = (AuthenticationException)request.getSession().getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
        String msg = exception.getMessage();

        if (exception instanceof UsernameNotFoundException) {
            msg = "用户名不正确";
        } else if (exception instanceof BadCredentialsException) {
            msg = "密码错误";
        } else if (exception instanceof DisabledException) {
            msg = "用户已被禁用";
        } else if (exception instanceof LockedException) {
            msg = "账户被锁定";
        } else if (exception instanceof AccountExpiredException) {
            msg = "账户过期";
        } else if (exception instanceof CredentialsExpiredException) {
            msg = "证书过期";
        }
        return msg;
    }
    @PostMapping("/user/login/failure")
    @ResponseBody
    public String failure(HttpServletRequest request){
        AuthenticationException exception = (AuthenticationException)request.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
        String msg = exception.getMessage();

        if (exception instanceof UsernameNotFoundException) {
            msg = "用户名不正确";
        } else if (exception instanceof BadCredentialsException) {
            msg = "密码错误";
        } else if (exception instanceof DisabledException) {
            msg = "用户已被禁用";
        } else if (exception instanceof LockedException) {
            msg = "账户被锁定";
        } else if (exception instanceof AccountExpiredException) {
            msg = "账户过期";
        } else if (exception instanceof CredentialsExpiredException) {
            msg = "证书过期";
        }
        return msg;
    }

    @PostMapping("/user/login/success")
    @ResponseBody
    public String success(){
       return "登录成功"}

值得注意的是,这个东西我测试了几次,是成功的,如果你测试到失败了,请务必留下信息。
另外在需要抛出自定义信息的时候,可以创建AuthenticationException的内部类转发到该接口,如校验验证码的时候:


public class VerifyFilter extends OncePerRequestFilter {
    private final Logger logger = LoggerFactory.getLogger("VerifyFilter");
    private static final PathMatcher pathMatcher = new AntPathMatcher();

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        if(isProtectedUrl(request)) {
            String verifyCode = request.getParameter("verifyCode");
            if(StringUtils.isEmpty(verifyCode)){
                error(request, response, new AuthenticationException("验证码不能为空"){});
            } else if(!validateVerify(verifyCode)) {
                error(request, response, new AuthenticationException("验证码输入错误"){});
            } else {
                filterChain.doFilter(request,response);
            }
        } else {
            filterChain.doFilter(request,response);
        }

    }

    private boolean validateVerify(String inputVerify) {
        //获取当前线程绑定的request对象
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        // 不分区大小写
        // 这个validateCode是在servlet中存入session的名字
        String validateCode = ((String) request.getSession().getAttribute("loginVerifyCode")).toLowerCase();
        inputVerify = inputVerify.toLowerCase();

        logger.info("验证码:" + validateCode + " 用户输入:" + inputVerify);
        return validateCode.equals(inputVerify);
    }

    // 拦截 /base/user/login
    private boolean isProtectedUrl(HttpServletRequest request) {
        return "POST".equals(request.getMethod()) && pathMatcher.match("/base/user/login", request.getServletPath());
    }

    private void error(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws ServletException, IOException {
        //手动设置异常
        request.setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION,exception);
        // 转发到错误Url
        request.getRequestDispatcher("/user/login/failure").forward(request,response);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

艳阳高照中最亮的星

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值