Reference:
1.Spring Boot + Spring Security + RESTful API的使用方法
https://zhuanlan.zhihu.com/p/33835975
2.How to make a custom Username Password Authentication Filter with Spring Security
https://leaks.wanari.com/2017/11/28/how-to-make-custom-usernamepasswordauthenticationfilter-with-spring-security/
Code download:
https://drive.google.com/file/d/1b6vZTSLRnhIncM7At40dqCbQwD4TVZNX/view?usp=sharing
HomeController.java
package com.rice.cool.controller;
import java.security.Principal;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class HomeController {
@RequestMapping("/")
@ResponseBody
public String home(){
return "首頁(不需登入即可瀏覽)";
}
@RequestMapping("/hello")
@ResponseBody
public String hello(HttpServletRequest req){
Principal principal = req.getUserPrincipal();
String name = principal.getName();
return "您好 " + name + ": 歡迎(需要登入才能瀏覽)";
}
}
WebSecurityConfig.java
package com.rice.cool.config;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;
/*
* reference:
* https://zhuanlan.zhihu.com/p/33835975
* https://leaks.wanari.com/2017/11/28/how-to-make-custom-usernamepasswordauthenticationfilter-with-spring-security/
* */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomAuthenticationProvider authProvider;
@Autowired
private CustomLoginHandler customLoginHandler;
@Autowired
private CustomLogoutHandler customLogoutHandler;
@Autowired
private CustomAccessDeniedHandler customAccessDeniedHandler;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// .csrf().disable()
.authorizeRequests()
.antMatchers("/", "/login").permitAll()
.anyRequest().authenticated()
.and()
// .httpBasic()
// .and()
.logout()
.logoutUrl("/logout")
.addLogoutHandler(customLogoutHandler) // 登出前调用,可用于日志
.logoutSuccessHandler(customLogoutHandler); // 登出后调用,用户信息已不存在
http
.exceptionHandling()
.accessDeniedHandler(customAccessDeniedHandler) // 已登入用户的权限错误
.authenticationEntryPoint(customAccessDeniedHandler); // 未登入用户的权限错误
http
.csrf()
.ignoringAntMatchers("/login"); // 登入API不启用CSFR检查
http
.addFilterBefore(
customAuthFilter(),
UsernamePasswordAuthenticationFilter.class
);
// http
// .addFilterAt(
// customAuthFilter(),
// UsernamePasswordAuthenticationFilter.class
// );
}
@Bean
public CustomAuthenticationFilter customAuthFilter() throws Exception {
CustomAuthenticationFilter filter = new CustomAuthenticationFilter();
filter.setAuthenticationSuccessHandler(customLoginHandler);
filter.setAuthenticationFailureHandler(customLoginHandler);
filter.setAuthenticationManager(authenticationManager());
filter.setFilterProcessesUrl("/login");
return filter;
}
@Component
public static class CustomAccessDeniedHandler implements AuthenticationEntryPoint, AccessDeniedHandler {
// NoLogged Access Denied
@Override
public void commence(HttpServletRequest req, HttpServletResponse resp, AuthenticationException authEx) throws IOException {
System.out.println("AccessDenied commence:");
resp.sendRedirect("/");
}
// Logged Access Denied
@Override
public void handle(HttpServletRequest req, HttpServletResponse resp, AccessDeniedException accessDeniedEx) throws IOException {
System.out.println("AccessDenied handle:");
}
}
@Component
public static class CustomLoginHandler implements AuthenticationSuccessHandler, AuthenticationFailureHandler {
// Login Success
@Override
public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication auth) throws IOException {
System.out.println("Login success:");
resp.sendRedirect("/hello");
}
// Login Failure
@Override
public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp, AuthenticationException ex) throws IOException {
System.out.println("Login failure:");
}
}
@Component
public static class CustomLogoutHandler implements LogoutHandler, LogoutSuccessHandler {
// Before Logout
@Override
public void logout(HttpServletRequest req, HttpServletResponse resp, Authentication auth) {
System.out.println("Logout logout:");
}
// After Logout
@Override
public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication auth) throws IOException {
System.out.println("Logout success:");
}
}
}
CustomAuthenticationFilter.java
package com.rice.cool.config;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse resp) throws AuthenticationException {
UsernamePasswordAuthenticationToken auth
= new UsernamePasswordAuthenticationToken("Rice", null);
setDetails(req, auth); // Allow subclasses to set the "details" property
return this.getAuthenticationManager().authenticate(auth);
}
}
CustomAuthenticationProvider.java
package com.rice.cool.config;
import java.util.ArrayList;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
String acc = authentication.getName();
//String pwd = authentication.getCredentials().toString();
return new UsernamePasswordAuthenticationToken(acc, null, new ArrayList<>());
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
留言列表