[Spring Security] 表单登录通过配置自定义登录页面,以及自定义认证成功/失败处理机制

Base on [Spring Security] Spring Security基于表单的登录认证

1.目录结构

[Spring Security] 表单登录通过配置自定义登录页面,以及自定义认证成功/失败处理机制_第1张图片

2.配置自定义登录页

[Spring Security] 表单登录通过配置自定义登录页面,以及自定义认证成功/失败处理机制_第2张图片

通过配置SecurityProperties,MyProperties,SecurityCoreConfig来读取resources文件夹下application.properties中相关配置项。

SecurityProperties:

package com.security.properties;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * @author ShotMoon
 */
@Data
@ConfigurationProperties(prefix = "shotmoon.security")//读取application.properties中以"shotmoon.security"开头的配置项,并写入myProperties对象中
public class SecurityProperties {
    
    //注意,对象名myProperties要跟application.properties中shotmoon.security(即prefix)后面相同
    private MyProperties myProperties = new MyProperties();

}

MyProperties:

package com.security.properties;

import lombok.Data;

/**
 * @author ShotMoon
 */
@Data
public class MyProperties {
    //注意,属性名loginPage跟application.properties相应配置名务必保持一致
    private String loginPage = "/default-login.html";
}

SecurityCoreConfig:

package com.security;

import com.security.properties.SecurityProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

/**
 * @author ShotMoon
 */
@Configuration
@EnableConfigurationProperties(SecurityProperties.class)
public class SecurityCoreConfig {

}

application.properties:

spring.datasource.driver-class-name = com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/security?useUnicode=yes&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=qwe123

security.basic.enabled=false

spring.session.store-type=none

//对应MyProperties中相关同名属性
shotmoon.security.myProperties.loginPage = /myLoginPage.html

配置后,初次访问服务会自动跳转到我们配置的自定义登录页(随便写的,略丑)

[Spring Security] 表单登录通过配置自定义登录页面,以及自定义认证成功/失败处理机制_第3张图片

3.自定义认证成功/失败处理

Spring Security默认的认证处理方式有时候并不能满足我们的需求,尤其当下前后端分离开发已成趋势的情况下,认证完成后返回html的形式并不利于我们分离开发,下面我们研究下如何用Spring Security自带的AuthenticationSuccessHandler,AuthenticationFailureHandler来解决这个问题。

MyAuthenticationSuccessHandler:

package com.security.authentication;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author ShotMoon
 */
@Component
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {

        logger.info("登录成功");

        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(objectMapper.writeValueAsString(authentication));//将java对象转成json字符串写入response,Authtication参数中包含我们的认证信息  
    }
}

AuthenticationFailureHandler:

package com.security.authentication;


import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private ObjectMapper objectMapper;
    
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {

        logger.info("登陆失败");

        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(objectMapper.writeValueAsString(exception));//将异常写入response中,显示在页面上
    }
}

然后在SecurityConfig中进行配置使其生效:

SecurityConfig:

package com.security.config;

import com.security.authentication.MyAuthenticationFailureHandler;
import com.security.authentication.MyAuthenticationSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @author ShotMoon
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Autowired
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;

    @Autowired
    private MyAuthenticationFailureHandler myAuthenticationFailureHandler;

    /**
     * @description :
     * @param : [http]
     * @return : void
     * @date : 2018/5/13 13:41
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.formLogin()
                .loginPage("/authentication/require")
                .loginProcessingUrl("/authentication/form")
                .successHandler(myAuthenticationSuccessHandler)//配置successHandler
                .failureHandler(myAuthenticationFailureHandler)//配置failureHandler
                .and()
                .authorizeRequests()
                .antMatchers(
                        "/loginPage.html",
                        "/myLoginPage.html",
                        "/authentication/require"

                ).permitAll()
                .anyRequest()
                .authenticated()
                .and()
                .csrf().disable();
    }
}

完成,看下效果:

登陆成功,显示认证信息:

[Spring Security] 表单登录通过配置自定义登录页面,以及自定义认证成功/失败处理机制_第4张图片

登陆失败,显示异常信息:

[Spring Security] 表单登录通过配置自定义登录页面,以及自定义认证成功/失败处理机制_第5张图片

这样我们就可以自定义认证完成处理机制了,快试试吧。


你可能感兴趣的:(Spring)