Spring Security自定义用户认证
This commit is contained in:
parent
c05153ac98
commit
7226c3c291
|
|
@ -0,0 +1,58 @@
|
|||
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>cc.mrbird</groupId>
|
||||
<artifactId>Security</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Security</name>
|
||||
<description>Demo project for Spring Boot</description>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>1.5.14.RELEASE</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<!-- spring-boot-starter-security -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.7</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package cc.mrbird;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SecurityApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SecurityApplication.class, args);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
package cc.mrbird.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class MyUser implements Serializable {
|
||||
private static final long serialVersionUID = 3497935890426858541L;
|
||||
|
||||
private String userName;
|
||||
|
||||
private String password;
|
||||
|
||||
private boolean accountNonExpired = true;
|
||||
|
||||
private boolean accountNonLocked= true;
|
||||
|
||||
private boolean credentialsNonExpired= true;
|
||||
|
||||
private boolean enabled= true;
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public boolean isAccountNonExpired() {
|
||||
return accountNonExpired;
|
||||
}
|
||||
|
||||
public void setAccountNonExpired(boolean accountNonExpired) {
|
||||
this.accountNonExpired = accountNonExpired;
|
||||
}
|
||||
|
||||
public boolean isAccountNonLocked() {
|
||||
return accountNonLocked;
|
||||
}
|
||||
|
||||
public void setAccountNonLocked(boolean accountNonLocked) {
|
||||
this.accountNonLocked = accountNonLocked;
|
||||
}
|
||||
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return credentialsNonExpired;
|
||||
}
|
||||
|
||||
public void setCredentialsNonExpired(boolean credentialsNonExpired) {
|
||||
this.credentialsNonExpired = credentialsNonExpired;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package cc.mrbird.handler;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
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 {
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper mapper;
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException exception) throws IOException {
|
||||
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
|
||||
response.setContentType("application/json;charset=utf-8");
|
||||
response.getWriter().write(mapper.writeValueAsString(exception.getMessage()));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package cc.mrbird.handler;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.DefaultRedirectStrategy;
|
||||
import org.springframework.security.web.RedirectStrategy;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
||||
import org.springframework.security.web.savedrequest.RequestCache;
|
||||
import org.springframework.security.web.savedrequest.SavedRequest;
|
||||
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 MyAuthenticationSucessHandler implements AuthenticationSuccessHandler {
|
||||
|
||||
// private RequestCache requestCache = new HttpSessionRequestCache();
|
||||
|
||||
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
|
||||
//
|
||||
// @Autowired
|
||||
// private ObjectMapper mapper;
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
|
||||
Authentication authentication) throws IOException {
|
||||
// response.setContentType("application/json;charset=utf-8");
|
||||
// response.getWriter().write(mapper.writeValueAsString(authentication));
|
||||
// SavedRequest savedRequest = requestCache.getRequest(request, response);
|
||||
// System.out.println(savedRequest.getRedirectUrl());
|
||||
// redirectStrategy.sendRedirect(request, response, savedRequest.getRedirectUrl());
|
||||
redirectStrategy.sendRedirect(request, response, "/index");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package cc.mrbird.security.browser;
|
||||
|
||||
import cc.mrbird.handler.MyAuthenticationFailureHandler;
|
||||
import cc.mrbird.handler.MyAuthenticationSucessHandler;
|
||||
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;
|
||||
|
||||
@Configuration
|
||||
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Autowired
|
||||
private MyAuthenticationSucessHandler authenticationSucessHandler;
|
||||
|
||||
@Autowired
|
||||
private MyAuthenticationFailureHandler authenticationFailureHandler;
|
||||
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.formLogin() // 表单登录
|
||||
// http.httpBasic() // HTTP Basic
|
||||
.loginPage("/authentication/require") // 登录跳转 URL
|
||||
.loginProcessingUrl("/login") // 处理表单登录 URL
|
||||
.successHandler(authenticationSucessHandler) // 处理登录成功
|
||||
.failureHandler(authenticationFailureHandler) // 处理登录失败
|
||||
.and()
|
||||
.authorizeRequests() // 授权配置
|
||||
.antMatchers("/authentication/require", "/login.html").permitAll() // 登录跳转 URL 无需认证
|
||||
.anyRequest() // 所有请求
|
||||
.authenticated() // 都需要认证
|
||||
.and().csrf().disable();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package cc.mrbird.security.browser;
|
||||
|
||||
import cc.mrbird.domain.MyUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
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;
|
||||
|
||||
@Configuration
|
||||
public class UserDetailService implements UserDetailsService {
|
||||
|
||||
@Autowired
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
// 模拟一个用户,替代数据库获取逻辑
|
||||
MyUser user = new MyUser();
|
||||
user.setUserName(username);
|
||||
user.setPassword(this.passwordEncoder.encode("123456"));
|
||||
// 输出加密后的密码
|
||||
System.out.println(user.getPassword());
|
||||
|
||||
return new User(username, user.getPassword(), user.isEnabled(),
|
||||
user.isAccountNonExpired(), user.isCredentialsNonExpired(),
|
||||
user.isAccountNonLocked(), AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package cc.mrbird.web.controller;
|
||||
|
||||
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.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
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 MrBird
|
||||
*/
|
||||
@RestController
|
||||
public class BrowserSecurityController {
|
||||
|
||||
private RequestCache requestCache = new HttpSessionRequestCache();
|
||||
|
||||
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
|
||||
|
||||
@GetMapping("/authentication/require")
|
||||
@ResponseStatus(HttpStatus.UNAUTHORIZED)
|
||||
public String requireAuthentication(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
SavedRequest savedRequest = requestCache.getRequest(request, response);
|
||||
if (savedRequest != null) {
|
||||
String targetUrl = savedRequest.getRedirectUrl();
|
||||
if (StringUtils.endsWithIgnoreCase(targetUrl, ".html"))
|
||||
redirectStrategy.sendRedirect(request, response, "/login.html");
|
||||
}
|
||||
return "访问的资源需要身份认证!";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package cc.mrbird.web.controller;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class TestController {
|
||||
@GetMapping("hello")
|
||||
public String hello() {
|
||||
return "hello spring security";
|
||||
}
|
||||
|
||||
@GetMapping("index")
|
||||
public Object index(Authentication authentication) {
|
||||
// return SecurityContextHolder.getContext().getAuthentication();
|
||||
return authentication;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
security:
|
||||
basic:
|
||||
enabled: true
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
.login-page {
|
||||
width: 360px;
|
||||
padding: 8% 0 0;
|
||||
margin: auto;
|
||||
}
|
||||
.form {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
background: #ffffff;
|
||||
max-width: 360px;
|
||||
margin: 0 auto 100px;
|
||||
padding: 45px;
|
||||
text-align: center;
|
||||
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24);
|
||||
}
|
||||
.form input {
|
||||
outline: 0;
|
||||
background: #f2f2f2;
|
||||
width: 100%;
|
||||
border: 0;
|
||||
margin: 0 0 15px;
|
||||
padding: 15px;
|
||||
box-sizing: border-box;
|
||||
font-size: 14px;
|
||||
}
|
||||
.form button {
|
||||
text-transform: uppercase;
|
||||
outline: 0;
|
||||
background: #4caf50;
|
||||
width: 100%;
|
||||
border: 0;
|
||||
padding: 15px;
|
||||
color: #ffffff;
|
||||
font-size: 14px;
|
||||
-webkit-transition: all 0.3 ease;
|
||||
transition: all 0.3 ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
.form button:hover,
|
||||
.form button:active,
|
||||
.form button:focus {
|
||||
background: #43a047;
|
||||
}
|
||||
.form .message {
|
||||
margin: 15px 0 0;
|
||||
color: #b3b3b3;
|
||||
font-size: 12px;
|
||||
}
|
||||
.form .message a {
|
||||
color: #4caf50;
|
||||
text-decoration: none;
|
||||
}
|
||||
.form .register-form {
|
||||
display: none;
|
||||
}
|
||||
.container {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
max-width: 300px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.container:before,
|
||||
.container:after {
|
||||
content: "";
|
||||
display: block;
|
||||
clear: both;
|
||||
}
|
||||
.container .info {
|
||||
margin: 50px auto;
|
||||
text-align: center;
|
||||
}
|
||||
.container .info h1 {
|
||||
margin: 0 0 15px;
|
||||
padding: 0;
|
||||
font-size: 36px;
|
||||
font-weight: 300;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
.container .info span {
|
||||
color: #4d4d4d;
|
||||
font-size: 12px;
|
||||
}
|
||||
.container .info span a {
|
||||
color: #000000;
|
||||
text-decoration: none;
|
||||
}
|
||||
.container .info span .fa {
|
||||
color: #ef3b3a;
|
||||
}
|
||||
body {
|
||||
background: #76b852; /* fallback for old browsers */
|
||||
background: -webkit-linear-gradient(right, #76b852, #8dc26f);
|
||||
background: -moz-linear-gradient(right, #76b852, #8dc26f);
|
||||
background: -o-linear-gradient(right, #76b852, #8dc26f);
|
||||
background: linear-gradient(to left, #76b852, #8dc26f);
|
||||
font-family: Lato,"PingFang SC","Microsoft YaHei",sans-serif;
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>登录</title>
|
||||
<link rel="stylesheet" href="css/login.css" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<form class="login-page" action="/login" method="post">
|
||||
<div class="form">
|
||||
<h3>账户登录</h3>
|
||||
<input type="text" placeholder="用户名" name="username" required="required"/>
|
||||
<input type="password" placeholder="密码" name="password" required="required"/>
|
||||
<button type="submit">登录</button>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue