close

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);
    }
}
 

 

arrow
arrow
    全站熱搜

    Ping 發表在 痞客邦 留言(0) 人氣()