SpringBoot SpringSecurity 登錄、登出自定義與HttpSecurity配置

SpringBoot SpringSecurity 登錄、登出自定義與HttpSecurity配置 

  • yml中的變量配置
  ############################ --  認證 -- ############################
security-fig:
  login-url:  /login
  login-processing-url: /loginProcess
  error-url:  /loginFail
  logout-url: /signout
  swagger-url:  /doc
  • HttpSecurity配置 
package com.config.security;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;

/**
 * Security fig
 */
@Slf4j
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)//開啓方法控制註解 @Secured、@PreAuthorize、@PostAuthorize
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Value( "${security-fig.login-url}" )
    private String loginUrl;
    @Value( "${security-fig.login-processing-url}" )
    private String loginProcessingUrl;
    @Value( "${security-fig.error-url}" )
    private String errorUrl;
    @Value( "${security-fig.logout-url}" )
    private String logoutUrl;

    @Autowired
    private CustomLogoutService customLogoutService;

    @Bean
    UserDetailsService customUserService(){
        return new CustomLoginService();
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .portMapper(  )
                .http( 80 )
                .mapsTo( 443 )
                .and()
                .authorizeRequests()//登錄配置
                .antMatchers( "/sys/**" ).permitAll()//允許訪問匹配的路徑
                .antMatchers( "/public/**" ).permitAll()
                .antMatchers( "/static/**" ).permitAll()
                .antMatchers( "/templates/**" ).permitAll()
                .anyRequest().authenticated()//以上配置除外,其它需要認證
                .and()
                .csrf().disable()//關閉post限制
                .formLogin()
                .loginPage( loginUrl )//登錄頁面
                .loginProcessingUrl(loginProcessingUrl)//登錄action 提交地址
//                .defaultSuccessUrl( "/index.html" )//這裏指定的是靜態頁面,必須加後綴,如果不指定,就走路徑爲“/”的方法
//                .failureUrl( "/login?error" )
                .failureUrl(errorUrl)//登錄失敗處理方法
                .permitAll()
                .and()
                .logout()//登出配置
                .logoutUrl(logoutUrl)
                .deleteCookies("JSESSIONID")//登出清理cookie
                .logoutSuccessHandler( customLogoutService )//登出實現類
                .permitAll();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        //設置靜態資源不要攔截
        web.ignoring().antMatchers( "/public/**","/static/**","/templates/**");
    }

    @Autowired
    private SecurityAuthenticationProvider provider;//注入我們自己的AuthenticationProvider

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //走默認認證
//        auth.userDetailsService( customUserService() ).passwordEncoder( new PasswordConfig() );
        //走自定義認證
        auth.authenticationProvider(provider);
    }


@Autowired
    private SecurityAuthenticationProvider provider;//注入我們自己的AuthenticationProvider

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //走默認認證
//        auth.userDetailsService( customUserService() ).passwordEncoder( new PasswordConfig() );
        //走自定義認證
        auth.authenticationProvider(provider);


}
  • 登錄邏輯實現類
package com.config.security;


import java.util.Collection;
import java.util.Date;

import com.ll.admin.dao.LoginRepository;
import com.ll.admin.domain.Login;
import com.utils.EncryptionUtil;
import com.utils.MD5;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.stereotype.Component;


/**
 * 登錄邏輯實現
 */
@Component
@Slf4j
public class SecurityAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    private UserDetailsService userDetailService;
    @Autowired
    private LoginRepository loginRepository;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        WebAuthenticationDetails details =(WebAuthenticationDetails) authentication.getDetails();
        String remoteAddress = details.getRemoteAddress();
        remoteAddress = "0:0:0:0:0:0:0:1".equals( remoteAddress ) ? "127.0.0.1" : remoteAddress; //訪問IP
        String userName = authentication.getName();	// 這個獲取表單輸入中返回的用戶名;
        String password = authentication.getCredentials().toString();	// 這個是表單中輸入的密碼;
        Login loginData = (Login) userDetailService.loadUserByUsername(userName);
Collection<? extends GrantedAuthority> authorities = loginData.getAuthorities();
        // 構建返回的用戶登錄成功的token

        return new UsernamePasswordAuthenticationToken(loginData, password, authorities);
    }

    @Override
    public boolean supports(Class<?> authentication) {
        // TODO Auto-generated method stub
        // 這裏直接改成retrun true;表示是支持這個執行
        return true;
    }
}
  • 登出邏輯實現
package com.config.security;

import com.ll.admin.dao.LoginRepository;
import com.ll.admin.domain.Login;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;

/**
 * 登出
 * 默認被 /signout 請求
 */
@Slf4j
@Component
public class CustomLogoutService implements LogoutSuccessHandler {

    @Value( "${server.servlet.context-path}" )
    private String contextPath;
    @Value( "${security-fig.login-url}" )
    private String loginUrl;

    @Autowired
    private LoginRepository loginRepository;

    @Override
    public void onLogoutSuccess(HttpServletRequest request,
                                HttpServletResponse response,
                                Authentication authentication)
            throws IOException, ServletException {

        //默認被 /signout 請求,這裏寫登出前要做的事 
        response.sendRedirect( contextPath + loginUrl );
    }
}
  •  成功與錯誤跳轉
  • Controller 用
    @AuthenticationPrincipal UserDetails userDetails 獲取當前用戶信息
  • 也可以在session中提取當前用戶信息
    HttpSession session = request.getSession();
    SecurityContextImpl ssc = (SecurityContextImpl) session.getAttribute( "SPRING_SECURITY_CONTEXT" );
    Authentication authentication = ssc.getAuthentication();
    Login details =(Login) authentication.getPrincipal();
  • 錯誤跳轉中 運用session獲取異常信息
  • HttpSession session = request.getSession();
    Object badCredentialsException = session.getAttribute( "SPRING_SECURITY_LAST_EXCEPTION" );
package com.config.security;

import com.ll.admin.dto.Msg;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
 * 登錄跳轉配置
 */
@Slf4j
@Controller
public class RequestController {

    /**
     * 成功首頁
     * @param userDetails
     * @param model
     * @return
     */
    @RequestMapping("/")
    public String index (@AuthenticationPrincipal UserDetails userDetails, Model model){
        Msg msg = new Msg( "測試標題", "測試內容", "額外信息,只有管理員可以看到!" );
        model.addAttribute( "msg",msg );
        return "index";
    }

    /**
     * 登錄失敗返回接口
     * @param request
     * @param model
     * @return
     */
    @RequestMapping("/loginFail")
    public String loginFail (HttpServletRequest request, Model model){
        HttpSession session = request.getSession();
        Object badCredentialsException = session.getAttribute( "SPRING_SECURITY_LAST_EXCEPTION" );
        String badCredentialsExceptionStr = badCredentialsException.toString();
        String msg = badCredentialsExceptionStr.split( ":" )[1];
        //錯誤消息提示
        model.addAttribute( "msg",msg);
        return "login";
    }


}

隨筆記錄,方便學習

2020-07-03

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章