自定义登录页面 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 idea
the spring
tools to create and introduce springboot
and springsecruity
package
The final pom.xml
code 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 SimpleResponse
interface 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 WebSecurityConfigurerAdapter
to 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 UserDetailsService
implement 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