springsecurity develop form-based authentication - personalized user certification process

自定义登录页面        http.formLogin().loginPage("/signin.html") 
自定义登录成功处理     AuthenticationSuccessHandler
自定义登录失败处理     AuthenticationFailHandler

The final effect is achieved when the html page will jump to access the login page, and customize the logon process successfully, and custom logon failures in order, and when accessing a non-html page requests an exception is thrown

1. Create a new project

Use ideathe springtools to create and introduce springbootand springsecruitypackage

The final pom.xmlcode is as follows

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo-spring-secruity</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo-spring-secruity</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.9</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Write SimpleResponseinterface for processing an output of the abnormality information

package com.example.demospringsecruity.support;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

/**
 *  一个简单的响应对象
 * @author john
 * @date 2020/1/6 - 16:23
 */
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class SimpleResponse {
    private Object content;
}

2. Configure Custom Log

Through inheritance WebSecurityConfigurerAdapterto achieve custom configuration

package com.example.demospringsecruity.config;

import com.example.demospringsecruity.handle.MyAuthenticationFailureHandler;
import com.example.demospringsecruity.handle.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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @author john
 * @date 2020/1/6 - 10:07
 */
@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
    @Autowired
    MyAuthenticationFailureHandler myAuthenticationFailureHandler;

    //手动将PasswordEncoder注入到ioc容器中
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 表单登录
        http.formLogin()
                .loginPage("/auth/require")     //设置登录路由
                .loginProcessingUrl("/auth/form")  //设置登录处理url
                .successHandler(myAuthenticationSuccessHandler) // 设置自定义成功处理器
                .failureHandler(myAuthenticationFailureHandler) // 设置自定义失败处理器
                .and()
                .authorizeRequests()     // 身份认证设置
                .antMatchers("/signin.html").permitAll() //该路由不需要身份认账
                .antMatchers("/auth/*").permitAll() //该路由不需要身份认账
                .anyRequest()       //其他的路由均需要身份认证
                .authenticated()
                .and()
                .csrf()
                .disable();   //先禁用防止跨站脚本攻击的csrf token
    }

}

By implementing UserDetailsServiceimplement a custom user interface to authentication logic

package com.example.demospringsecruity.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

/**
 * @author john
 * @date 2020/1/6 - 10:32
 */
@Component
@Slf4j
public class MyUserDetailsService implements UserDetailsService {
    //这里可以注入mapper或者repository的dao对象来实现数据校验逻辑操作
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        log.info("用户名:" + username);
        //这里密码应该从数据库中取出,暂时先使用加密生成
        String password = passwordEncoder.encode("123456");
        return new User(username,
                password,
                true,                 // 账户是否可用
                true,        // 账户是否过期
                true,     // 密码是否过期
                true,        //账户是否被锁定
                AuthorityUtils.commaSeparatedStringToAuthorityList("admin") //授权集合
        );
    }
}

Write a custom login page

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
<h2>标准登录页面</h2>
<h3>表单登录</h3>
<form action="/auth/form" method="post">
    <table>
        <tr>
            <td>用户名:</td>
            <td><input type="text" name="username"></td>
        </tr>
        <tr>
            <td>密码:</td>
            <td><input type="password" name="password"></td>
        </tr>
        <tr>
            <td colspan="2">
                <button type="submit">登录</button>
            </td>
        </tr>
    </table>
</form>
</body>
</html>

3. Write access logic

When visiting html page will jump the login page when accessing non-html page requests an exception is thrown

package com.example.demospringsecruity.controller;

import com.example.demospringsecruity.support.SimpleResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

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

/**
 * @author john
 * @date 2020/1/6 - 16:03
 */
@RestController
@Slf4j
public class BrowserSecruityController {

    private RequestCache requestCache = new HttpSessionRequestCache();

    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

    //当需要身份认证时,跳转到这---如果是html页面请求跳转到登录页面,否则会被当成ajax异步请求,抛出异常
    @RequestMapping("/auth/require")
    @ResponseStatus(code = HttpStatus.UNAUTHORIZED)
    public SimpleResponse requireAuth(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //获取前一次的跳转请求
        SavedRequest savedRequest = requestCache.getRequest(request, response);
        if (savedRequest != null) {
            String targetUrl = savedRequest.getRedirectUrl();
            log.info("引发跳转请求的url是:" + targetUrl);
            if (StringUtils.endsWithIgnoreCase(targetUrl, ".html")) {
                redirectStrategy.sendRedirect(request, response, "/signin.html");
            }
        }

        return new SimpleResponse("访问的服务需要身份认证,请引导用户到登录页");
    }
}

4. Writing custom login process successfully

package com.example.demospringsecruity.handle;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
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 john
 * @date 2020/1/6 - 17:20
 */
@Component
@Slf4j
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        log.info("登录成功");
        //这里处理登录成功后就会json输出authentication里面的数据
        response.setContentType("application/json;charset-UTF-8");
        response.getWriter().write(objectMapper.writeValueAsString(authentication));
    }
}

5. Write custom login process fails

package com.example.demospringsecruity.handle;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
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;

/**
 * 自定义登录失败处理
 *
 * @author john
 * @date 2020/1/6 - 18:43
 */
@Component
@Slf4j
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
        log.info("登录失败");
        //这里处理登录失败后就会输出错误信息
        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
        response.setContentType("application/json;charset-UTF-8");
        response.getWriter().write(objectMapper.writeValueAsString(e));
    }
}

6. Test

6.1 Test Access<http://localhost:8081/aa>

6.2 Test Access<http://localhost:8081/index.html>

login successful

Login failed

7. Resources Code

Link: https: //share.weiyun.com/50cUdga Password: k2r9ie

Guess you like

Origin www.cnblogs.com/ifme/p/12157999.html