Spring Security 入門(基本使用)


Spring Security 入門(基本使用)

這幾天看了下b站關於 spring security 的學習視頻,不得不說 spring security 有點復雜,腦袋有點懵懵的,在此整理下學習內容。

1、入門

個人理解url 的訪問流程大致如下:

spring security 訪問url路徑圖

1.1、什么是 spring security

  • spring security 是一個比 shiro 更加強大的安全管理框架,權限顆粒度更細。
  • 源自於 spring 家族,能跟 springboot 無縫整合,對 oauth2 的支持也更好。

1.2、依賴配置

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.lin</groupId>
    <artifactId>spring-security-study</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-security-study</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-test</artifactId>
            <scope>test</scope>
        </dependency>
        
        <!-- spring security -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- mysql驅動 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!-- springboot整合mybatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>
        <!-- thymeleaf spring security5 依賴 -->
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
        </dependency>
        <!-- thymeleaf 依賴 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
    </dependencies>

1.3、測試接口

添加一個簡單的 /hello 接口:

@RequestMapping("/hello")
@ResponseBody
public String hello() {
    return "恭喜你登錄成功";
}

啟動項目,訪問 /hello 接口,會發現自動跳轉到 spring security 提供的登錄頁面:

image-20210513103731379

默認的 username 為 :user,password 在項目啟動時隨機生成,具體如下:

image-20210513104009820

登錄成功后即可訪問 /hello接口。

2、自定義登錄頁面、登錄成功處理器、登錄失敗處理器、異常處理器、權限邏輯

項目結構如下:

image-20210514174013950

2.1、自定義登錄頁面

1、登錄頁面 login.html :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登陸</title>
</head>
<body>
<form method="post" action="/login">
    用戶名:<input type="text" name="username123"><br />
    密碼:<input type="password" name="password123"><br />
    <button type="submit">立即登陸</button>
</form>
</body>
</html>

2、登錄成功跳轉頁 main.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
登錄成功!!!
<a href="/main1.html">跳轉權限頁</a>
</body>
</html>

3、登錄失敗跳轉頁 error.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
登錄失敗,請重新登錄<a href="/login.html">跳轉</a>
</body>
</html>

4、權限頁 main1.html

**main.html **如果有權限,則能訪問該頁面,否則報 403

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
權限控制!!!</a>
</body>
</html>

2.2、自定義登錄邏輯

自定義登錄邏輯主要用於對用戶名和密碼進行校驗,需要實現 UserDetailService 接口

@Service
public class UserDetailServiceImpl implements UserDetailsService {

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println("=======執行自定義登錄邏輯====");
        //校驗用戶名,實際環境中需要從數據庫查詢
        if (!username.equals("admin")) {
            throw new UsernameNotFoundException("用戶不存在");
        }
        //比較密碼,實際需要從數據庫取出原密碼校驗,框架會自動讀取登錄頁面的密碼
        String password = bCryptPasswordEncoder.encode("123456");
        //返回UserDetails,實際開發中可拓展UserDetails
        return new User(username, password, 
                        //自定義權限
                        AuthorityUtils.commaSeparatedStringToAuthorityList("permission1"));
    }
}

2.3、自定義登錄成功處理器

登錄成功處理器實現 AuthenticationSuccessHandler 接口

public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    private String url;

    public MyAuthenticationSuccessHandler(String url) {
        this.url = url;
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        //獲取IP地址
        System.out.println(request.getRemoteAddr());
        //獲取認證用戶信息
        User user = (User) authentication.getPrincipal();
        System.out.println("=====" + user.getAuthorities());
        //重定向
        response.sendRedirect(url);
    }
}

2.4、自定義登錄失敗處理器

登錄失敗處理器實現 AuthenticationFailureHandler接口

public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {

    private String url;

    public MyAuthenticationFailureHandler(String url) {
        this.url = url;
    }

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        //重定向
        response.sendRedirect(url);
    }
}

2.5、自定義異常處理器

@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        //響應狀態403
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        //返回格式
        response.setHeader("Content-Type", "application/json;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.write("{status: \"error\",\"msg\": \"權限不足,請聯系管理員\"}");
        writer.flush();
        writer.close();
    }
}

2.6、配置 Spring Security

該類是 Spring Security 的配置類, 繼承 WebSecurityConfigurerAdapter

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyAccessDeniedHandler myAccessDeniedHandler;
    
    /**
     * 指定密碼加密的方法
     *
     * @return
     */
    @Bean
    public BCryptPasswordEncoder getPasswordEncode() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //表單提交
        http.formLogin()
                //自定義用戶名和密碼參數
                .usernameParameter("username123")
                .passwordParameter("password123")
                //自定義登錄頁面
                .loginPage("/showLogin")
                //必須和表單提交的接口一樣,執行自定義登錄邏輯
                .loginProcessingUrl("/login")
                //自定義登錄成功處理器
                .successHandler(new MyAuthenticationSuccessHandler("/main.html"))
                //自定義登錄失敗處理器
                .failureHandler(new MyAuthenticationFailureHandler("/error.html"));
        
        //授權
        http.authorizeRequests()
                //放行/login.html,不需要認證
                .antMatchers("/showLogin").permitAll()
                //放行/error.html,不需要認證
                .antMatchers("/error.html").permitAll()
                //基於權限判斷
                .antMatchers("/main1.html").hasAuthority("permission1")
                //所有請求必須認證
                .anyRequest().authenticated();
        
        //異常處理器
        http.exceptionHandling().accessDeniedHandler(myAccessDeniedHandler);

        //關閉csrf防護
        http.csrf().disable();
    }

    /**
     * 放行靜態資源,css,js,images
     * 
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/css/**", "/js/**")
        .antMatchers("/**/*.png");
    }
}

2.7、運行測試

1、運行后訪問 http://localhost:8080/login.html,加載的自定義登錄頁面如下:

注意我在前面的自定義登錄邏輯中寫死了 username: adminpassword:123456

image-20210513145444184

2、點擊立即登陸按鈕,根據登錄成功處理器重定向到登錄成功頁 main.html

image-20210513145901250

3、前面的代碼中,如果登錄成功則擁有permission1權限,而訪問權限頁剛好需要 permission1 權限,

點擊跳轉權限頁,來到權限頁** main1.html**:

image-20210513150430940

4、修改登錄成功的權限為 permission2,

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    System.out.println("=======執行自定義登錄邏輯====");
    //校驗用戶名,實際環境中需要從數據庫查詢
    if (!username.equals("admin")) {
        throw new UsernameNotFoundException("用戶不存在");
    }
    //比較密碼,實際需要從數據庫取出原密碼校驗,框架會自動讀取登錄頁面的密碼
    String password = bCryptPasswordEncoder.encode("123456");
    //返回UserDetails,實際開發中可拓展UserDetails
    return new User(username, password,
            //修改權限為permisson2
            AuthorityUtils.commaSeparatedStringToAuthorityList("permission2"));
}

再次訪問需要 permission1 權限的權限頁,打印以下錯誤:

image-20210513154239657

5、如果 username 或者 password 錯誤,根據登錄失敗處理器重定向到登錄失敗頁 error.html:

image-20210513151019099

3、自定義用戶退出登錄

3.1、默認的退出登錄

spring security 有默認的退出登錄接口,直接訪問 /logout 接口,就能實現退出登錄,下面是簡單演示:

main.html 添加退出登錄的訪問鏈接logout:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
登錄成功!!!
<a href="/logout">退出</a>
<a href="/main1.html">跳轉權限頁</a>
</body>
</html>

直接就能退出了,簡不簡單呢?默認跳轉到登錄頁:

image-20210513171702339

仔細觀察,發現訪問路徑拼接了 ?logout 字符串,查看源碼可以發現默認的配置如下:

image-20210513172226418

3.2、自定義退出登錄

如果默認的退出登錄無法滿足,可以自定義處理器來解決。

3.2.1、自定義 LogoutHandler

默認情況下清除認證信息 (clearAuthentication),和Session 失效(invalidateHttpSession) 已經由內置的SecurityContextLogoutHandler 來完成。

這個 LogoutHandle 主要用來處理用戶信息。

/**
 * 登出接口處理器
 */
public class MyLogoutHandler implements LogoutHandler {
    @Override
    public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
        User user = (User) authentication.getPrincipal();
        //執行用戶信息操作,如記錄用戶下線時間...
    }
}
3.2.2、自定義 LogoutSuccessHandler

這個 LogoutSuccessHandler 用於返回響應信息給前端,可以返回 json、重定向頁面。

注意配置這個處理器之后,就不需要配置 logoutSuccessUrl了。

/**
 * 登出成功處理器
 */
public class MyLogoutSuccessHandler implements LogoutSuccessHandler {

    private String url;

    public MyLogoutSuccessHandler(String url) {
        this.url = url;
    }
    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        //重定向
        response.sendRedirect(url);
    }
}
3.3.3、spring security 添加配置
@Override
protected void configure(HttpSecurity http) throws Exception {
    //表單提交
    http.formLogin()
        //自定義用戶名和密碼參數
        .usernameParameter("username123")
        .passwordParameter("password123")
        //自定義登錄頁面
        .loginPage("/login.html")
        //必須和表單提交的接口一樣,執行自定義登錄邏輯
        .loginProcessingUrl("/login")
        //自定義登錄成功處理器
        .successHandler(new MyAuthenticationSuccessHandler("/main.html"))
        //自定義登錄失敗處理器
        .failureHandler(new MyAuthenticationFailureHandler("/error.html"));
    //授權
    http.authorizeRequests()
        //放行/login.html,不需要認證
        .antMatchers("/login.html").permitAll()
        //放行/error.html,不需要認證
        .antMatchers("/error.html").permitAll()
        //基於權限判斷
        .antMatchers("/main1.html").hasAuthority("permission1")
        //所有請求必須認證
        .anyRequest().authenticated();

    //異常處理器
    http.exceptionHandling().accessDeniedHandler(myAccessDeniedHandler);

    //登出
    http.logout()
        //登出接口,與表單訪問接口一致
        .logoutUrl("/signLogout")
        //登出處理器
        .addLogoutHandler(new MyLogoutHandler())
        //登出成功后跳轉的頁面
        .logoutSuccessHandler(new MyLogoutSuccessHandler("/login.html"));

    //關閉csrf防護
    http.csrf().disable();
}
3.3.4、修改登出接口

main.html 修改如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
登錄成功!!!
<a href="/signLogout">退出</a>
<a href="/main1.html">跳轉權限頁</a>
</body>
</html>

運行測試后,返回 localhost://8080/login.html

4、基於注解的權限控制

4.1、權限注解參數

關於權限的注解參數共有三個:

  • @PreAuthorize:方法執行前進行權限檢查
  • @PostAuthorize:方法執行后進行權限檢查
  • @Secured:類似於 @PreAuthorize

4.2、啟動類添加 @EnableGlobalMethodSecurity

啟動類配置如下:

@SpringBootApplication
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class SpringSecurityStudyApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringSecurityStudyApplication.class, args);
    }
}

4.3、運行測試

4.3.1、修改 spring security 和 自定義登錄邏輯

successHander(登錄成功處理器) 修改為 successForwardUrl(登錄成功訪問路徑),刪除 permission1的權限判斷,改成訪問接口時進行權限判斷。

@Override
protected void configure(HttpSecurity http) throws Exception {
    //表單提交
    http.formLogin()
        //自定義用戶名和密碼參數
        .usernameParameter("username123")
        .passwordParameter("password123")
        //自定義登錄頁面
        .loginPage("/login.html")
        //必須和表單提交的接口一樣,執行自定義登錄邏輯
        .loginProcessingUrl("/login")
        //登錄成功跳轉的頁面,post請求
        .successForwardUrl("/toMain")
        //自定義登錄失敗處理器
        .failureHandler(new MyAuthenticationFailureHandler("/error.html"));
    //授權
    http.authorizeRequests()
        //放行/login.html,不需要認證
        .antMatchers("/login.html").permitAll()
        //放行/error.html,不需要認證
        .antMatchers("/error.html").permitAll()
        //所有請求必須認證
        .anyRequest().authenticated();

    //異常處理器
    http.exceptionHandling().accessDeniedHandler(myAccessDeniedHandler);

    //登出
    http.logout()
        //登出接口,與表單訪問接口一致
        .logoutUrl("/signLogout")
        //登出處理器
        .addLogoutHandler(new MyLogoutHandler())
        //登出成功后跳轉的頁面
        .logoutSuccessHandler(new MyLogoutSuccessHandler("/login.html"));

    //關閉csrf防護
    http.csrf().disable();
}

自定義登錄邏輯如下:

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    //校驗用戶名,實際環境中需要從數據庫查詢
    if (!username.equals("admin")) {
        throw new UsernameNotFoundException("用戶不存在");
    }
    //比較密碼,實際需要從數據庫取出原密碼校驗,框架會自動讀取登錄頁面的密碼
    String password = bCryptPasswordEncoder.encode("123456");
    //返回UserDetails,實際開發中可拓展UserDetails
    return new User(username, password,
                    //自定義權限
                    AuthorityUtils.commaSeparatedStringToAuthorityList("permission1"));
}
4.3.2、添加測試接口
//登錄成功跳轉頁
@PostMapping("/toMain")
//判斷是否擁有permission1的權限
@PreAuthorize("hasPermission('permission1')")
public String toMain() {
    //獲得認證用戶信息
    Object object = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    if (object instanceof UserDetails) {
        //進行一系列操作
    }
    return "redirect:main.html";
}
4.3.3、運行測試

登錄成功,通過 /toMain接口重定向到 main.html:

image-20210513232002281

5、自定義登錄過濾器

當默認的 UserDetailsService 無法滿足需求,例如增加圖形驗證碼校驗,此時可以自己創建登錄過濾器 UsernamePasswordAuthenticationFilter 及登錄認證處理 AuthenticationProvider,對業務邏輯進行拓展。

5.1、自定義身份認證處理

實現 AuthenticationProvider

/**
 * 登錄認證處理
 * @author Lin
 */
public class MyAuthenticationProvider implements AuthenticationProvider {

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = (String) authentication.getPrincipal();
        String password = (String) authentication.getCredentials();
        //校驗賬號,實際需要從DB查詢
        if (!username.equals("admin")) {
            throw new UsernameNotFoundException("用戶不存在");
        }
        //校驗密碼,實際需要加密並與DB的password比較
        if (!password.equals("123456")) {
            throw new InternalAuthenticationServiceException("密碼錯誤");
        }
        return new UsernamePasswordAuthenticationToken(username, password,
                //自定義權限
                AuthorityUtils.commaSeparatedStringToAuthorityList("permission1,ROLE_abc,/main.html"));
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return true;
    }
}

5.2、自定義登錄過濾器

實現 UsernamePasswordAuthenticationFilter

/**
* 登錄過濾器
* @author Lin
*/
public class MyUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

   public MyUsernamePasswordAuthenticationFilter() {
       //登錄成功處理器
       this.setAuthenticationSuccessHandler(new MyAuthenticationSuccessHandler("/main.html"));
       //登錄失敗處理器
       this.setAuthenticationFailureHandler(new MyAuthenticationFailureHandler("/error.html"));
   }

   @Override
   public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
       String username = request.getParameter("username123");
       String password = request.getParameter("password123");
       if (Strings.isBlank(username)) {
           throw new AuthenticationServiceException("賬戶不能為空");
       }
       if (Strings.isBlank(password)) {
           throw new AuthenticationServiceException("密碼不能為空");
       }
       UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
       setDetails(request,authenticationToken);
       return new MyAuthenticationProvider().authenticate(authenticationToken);
   }
}

5.3、修改spring security 的配置類

中間代碼忽略,改動部分如下,增加自定義登錄過濾器的配置

@Override
protected void configure(HttpSecurity http) throws Exception {
    //表單提交
    http.formLogin()
        //自定義用戶名和密碼參數
        .usernameParameter("username123")
        .passwordParameter("password123")
        //自定義登錄頁面
        .loginPage("/login.html")
        //必須和表單提交的接口一樣,執行自定義登錄邏輯
        .loginProcessingUrl("/login")
	....
    ....
    //自定義登錄過濾器
    http.addFilterBefore(new MyUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}

運行測試后,debug 發現賬號認證走的自定義登錄過濾器 MyUsernamePasswordAuthenticationFilter,說明配置成功。

6、基於動態權限的權限控制

上文演示了基於注解的權限控制,但在實際的開發中需要做到動態權限控制,spring security能夠支持動態權限,需要實現 FilterInvocationSecurityMetadataSourceAccessDecisionManager

6.1、自定義權限過濾器

權限過濾器實現 FilterInvocationSecurityMetadataSource,用於返回訪問 url 所需的權限。

注意:在添加權限過濾器后,所有的請求都會經過該過濾器,包括登錄頁面/login.html,即使 permitAll(),因此需要添加匿名角色ROLE_ANONYMOUS映射登錄頁面 login.html,如下面代碼的put("/login.html", "ROLE_ANONYMOUS")

/**
 * 權限過濾器
 *
 * @author Lin
 * @Description 返回url需要的權限
 */
@Component
public class MyFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    private static final Logger log = LoggerFactory.getLogger(MyFilterInvocationSecurityMetadataSource.class);

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        //獲取請求路徑
        String requestUrl = ((FilterInvocation) object).getRequestUrl();
        log.info("==========requestUrl:" + requestUrl);
        // 這里的需要從DB加載
        AntPathMatcher antPathMatcher = new AntPathMatcher();
        Map<String, String> urlRoleMap = new HashMap<String, String>() {{
            //登錄頁為匿名角色訪問
            put("/login.html", "ROLE_ANONYMOUS");
            put("/toMain", "ROLE_USER");
        }};
        List<String> roleList = new ArrayList<>();
        int i = 0;
        for (Map.Entry<String, String> entry : urlRoleMap.entrySet()) {
            if (antPathMatcher.match(entry.getKey(), requestUrl)) {
                roleList.add(entry.getValue());
            }
        }
        List<ConfigAttribute> configAttributes = SecurityConfig.createList(roleList.toArray(new String[roleList.size()]));
        return configAttributes;
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }
}

6.2、自定義權限決策管理器

權限決策管理器實現 AccessDecisionManager,判斷用戶是否有訪問 url 的權限。

/**
 * 權限決策管理器
 * @author Lin
 * @Description 根據url判斷用戶是否有訪問權限
 */
@Component
public class MyAccessDecisionManager implements AccessDecisionManager {
    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
        Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
        Iterator<ConfigAttribute> iterator = configAttributes.iterator();
        while (iterator.hasNext()) {
            String needPermission = iterator.next().getAttribute();
            for (GrantedAuthority authority : authorities) {
                if (authority.getAuthority().equals(needPermission)){
                    return;
                }
            }
        }
        throw new AccessDeniedException("權限不足");
    }

    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }
}

6.3、修改 sprIng security 的配置類

@Override
protected void configure(HttpSecurity http) throws Exception {

    //表單提交
    http.formLogin()
        //自定義用戶名和密碼參數
        .usernameParameter("username123")
        .passwordParameter("password123")
        //自定義登錄頁面
        .loginPage("/login.html")
        //必須和表單提交的接口一樣,執行自定義登錄邏輯
        .loginProcessingUrl("/login");

    //授權
    http.authorizeRequests()
        //動態權限控制
        .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
            @Override
            public <O extends FilterSecurityInterceptor> O postProcess(O object) {
                object.setSecurityMetadataSource(myFilterInvocationSecurityMetadataSource);
                object.setAccessDecisionManager(myAccessDecisionManager);
                return object;
            }
        })
        //放行/login.html,不需要認證
        .antMatchers("/login.html").permitAll()
        //放行/error.html,不需要認證
        .antMatchers("/error.html").permitAll();


    //異常處理器
    http.exceptionHandling().accessDeniedHandler(myAccessDeniedHandler);


    //登出
    http.logout()
        //登出接口,與表單接口一致
        .logoutUrl("/signLogout")
        //登出處理器
        .addLogoutHandler(new MyLogoutHandler())
        //登出成功后跳轉的頁面
        .logoutSuccessHandler(new MyLogoutSuccessHandler("/login.html"));

    //關閉csrf防護
    http.csrf().disable();

    //自定義登錄過濾器
    http.addFilterBefore(new MyUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}

這樣動態權限控制便配置完成。

7、參考資料

https://www.bilibili.com/video/BV1Cz4y1k7rd?from=search&seid=8886448532131988851

https://blog.csdn.net/zhaoxichen_10/article/details/88713799


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM