SpringSecurity(三)自定义登录成功与失败处理

通过前面两篇文章,我们已经知道了如何使用简单的配置来保护我们的应用了,根本不需要去管SpringSecurity的登录验证流程。如果我们需要自定义登录成功与失败处理,我们需要实现AuthenticationSuccessHandler接口和AuthenticationFailureHandler接口

1. 新建MyAuthenticationSuccessHandler类

@Component
@Slf4j
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    public static final String RETURN_TYPE = "html"; // 登录成功时,用来判断是返回json数据还是跳转html页面

    @Autowired
    private ObjectMapper objectMapper;

    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        log.info("登录成功");
        log.info("username=>" + request.getParameter("username"));
        if(RETURN_TYPE.equals("html")) {
            redirectStrategy.sendRedirect(request, response, "/user/index");
        } else {
            Map<String, Object> map = new HashMap<>();
            map.put("code","0");
            map.put("msg","登录成功");
            map.put("data",authentication);
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write(objectMapper.writeValueAsString(map));
        }
    }
}

2. 新建MyAuthenticationFailHandler类

@Component
@Slf4j
public class MyAuthenticationFailHandler implements AuthenticationFailureHandler {

    public static final String RETURN_TYPE = "html"; // 登录失败时,用来判断是返回json数据还是跳转html页面

    @Autowired
    private ObjectMapper objectMapper;

    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        log.info("登录失败:" + exception.getMessage());
        log.info("username=>" + request.getParameter("username"));

        if (RETURN_TYPE.equals("html")) {
            redirectStrategy.sendRedirect(request, response, "/login/index?error=true");
        } else {
            Map<String, Object> map = new HashMap<>();
            map.put("code","1002");
            map.put("msg","登录失败");
            map.put("data",exception.getMessage());
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write(objectMapper.writeValueAsString(map));
        }
    }
}

3. 修改SpringSecurityConfig类

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserService myUserService;

    @Autowired
    private MyAuthenticationSuccessHandler authenticationSuccessHandler;
    @Autowired
    private MyAuthenticationFailHandler authenticationFailHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/authentication/*","/login/*") // 不需要登录就可以访问
                .permitAll()
                .antMatchers("/user/**").hasAnyRole("USER") // 需要具有ROLE_USER角色才能访问
                .antMatchers("/admin/**").hasAnyRole("ADMIN") // 需要具有ROLE_ADMIN角色才能访问
                .anyRequest().authenticated()
                .and()
                    .formLogin()
                    .loginPage("/authentication/login") // 访问需要登录才能访问的页面,如果未登录,会跳转到该地址来
                    .loginProcessingUrl("/authentication/form")
                    .successHandler(authenticationSuccessHandler)
                    .failureHandler(authenticationFailHandler)
                ;
    }

    // 密码加密方式
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    // 重写方法,自定义用户
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserService); // 注入MyUserService,这样SpringSecurity会调用里面的loadUserByUsername(String s)
    }
}

4. LoginController

@Controller
public class LoginController {

    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

    public static final String RETURN_TYPE = "html"; // 需要登录时,用来判断是返回json数据还是跳转html页面

    // 如果用户访问的界面需要登录则会跳转到该路径,在这里判断是返回json格式的数据还是返回html页面
    @GetMapping("/authentication/login")
    @ResponseBody
    public Object authenticationLogin(HttpServletRequest request, HttpServletResponse response) throws IOException {
        if (RETURN_TYPE.equals("html")) {
            redirectStrategy.sendRedirect(request,response,"/login/index");
        }
        // 如果是需要返回json数据,则返回需要登录的信息提示
        Map<String, Object> map = new HashMap<>();
        map.put("code",1001);
        map.put("msg","需要登录");
        return map;
    }


    // 登录页面
    @GetMapping("/login/index")
    public String loginIndex() throws IOException {
        return "login";
    }
}

到这里已经配置完成了。

 

如果这样写的话,还存在一个问题,假设登录成功默认跳转到A页面。在没有登录的情况下访问B页面,此时会先跳转到登录页面,登录成功后,按照上面的逻辑应该是跳转到A页面,而我们是希望在登录成功之后直接跳转到B页面,那么该如何实现呢?

SpringSecurity已经有实现好的类直接供我们使用,修改后的代码如下:

@Component
@Slf4j
public class MyAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {

    public static final String RETURN_TYPE = "html"; // 登录成功时,用来判断是返回json数据还是跳转html页面

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        log.info("登录成功");
        log.info("username=>" + request.getParameter("username"));
        if(RETURN_TYPE.equals("html")) {
            super.setDefaultTargetUrl("/user/index"); // 设置默认登陆成功的跳转地址
            super.onAuthenticationSuccess(request, response, authentication);
        } else {
            Map<String, Object> map = new HashMap<>();
            map.put("code","0");
            map.put("msg","登录成功");
            map.put("data",authentication);
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write(objectMapper.writeValueAsString(map));
        }
    }
}

 

@Component
@Slf4j
public class MyAuthenticationFailHandler extends SimpleUrlAuthenticationFailureHandler {

    public static final String RETURN_TYPE = "html"; // 登录失败时,用来判断是返回json数据还是跳转html页面

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        log.info("登录失败:" + exception.getMessage());
        log.info("username=>" + request.getParameter("username"));

        if (RETURN_TYPE.equals("html")) {
            super.setDefaultFailureUrl("/login/index?error=true"); // 登录失败,跳转到登录界面
            super.onAuthenticationFailure(request, response, exception);
        } else {
            Map<String, Object> map = new HashMap<>();
            map.put("code","1002");
            map.put("msg","登录失败");
            map.put("data",exception.getMessage());
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write(objectMapper.writeValueAsString(map));
        }
    }
}

 

代码地址    https://github.com/923226145/SpringSecurity/tree/master/chapter3  

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
Spring Security提供了多种实现用户认证的方式,自定义登录可以通过以下步骤实现: 1. 创建一个类实现org.springframework.security.core.userdetails.UserDetailsService接口,该接口包含一个方法loadUserByUsername(String username),该方法用于根据用户名从数据源中获取用户信息并返回一个UserDetails对象。 2. 创建一个类实现org.springframework.security.authentication.AuthenticationProvider接口,该接口包含一个方法authenticate(Authentication authentication),该方法用于对用户进行认证,认证成功后返回一个Authentication对象。 3. 在Spring Security配置文件中配置自定义的UserDetailsService和AuthenticationProvider,例如: ``` @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Autowired private AuthenticationProvider authenticationProvider; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(authenticationProvider); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers("/login").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") .defaultSuccessUrl("/home") .failureUrl("/login?error") .usernameParameter("username") .passwordParameter("password") .permitAll() .and() .logout() .logoutSuccessUrl("/login?logout") .permitAll(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } ``` 4. 创建一个登录页面,例如: ``` <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Login</title> </head> <body> <h1>Login</h1> <form method="post" action="/login"> <label for="username">Username:</label> <input type="text" id="username" name="username" required autofocus><br><br> <label for="password">Password:</label> <input type="password" id="password" name="password" required><br><br> <button type="submit">Login</button> </form> </body> </html> ``` 5. 在控制器中处理登录请求,例如: ``` @Controller public class LoginController { @GetMapping("/login") public String getLoginPage() { return "login"; } @PostMapping("/login") public String login() { return "redirect:/home"; } @GetMapping("/home") public String getHomePage() { return "home"; } } ``` 以上就是自定义登录的实现步骤,需要注意的是,由于我们使用了自定义的UserDetailsService和AuthenticationProvider,所以在用户认证时需要调用这些类的方法。同时,我们还需要在Spring Security配置文件中配置登录页面、成功页面和失败页面等信息。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值