SpringBoot入門 (十四) Security安全控制


本文記錄在SpringBoot使用SpringSecurity進行安全訪問控制。

一 什么是Security

  Spring Security是一個能夠為基於Spring的企業應用系統提供聲明式的安全訪問控制解決方案的安全框架。它提供了一組可以在Spring應用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反轉Inversion of Control ,DI:Dependency Injection 依賴注入)和AOP(面向切面編程)功能,為應用系統提供聲明式的安全訪問控制功能,減少了為企業系統安全控制編寫大量重復代碼的工作。

  目前在我們項目中使用的是RBAC基於角色的權限訪問控制(Role-Based Access Control),用戶與角色關聯,角色與權限相關聯,用戶通過角色間接的得到權限。關系如下圖

  用戶:權限的擁有者

  角色:一些權限的集合

  權限:操作的對象或資源

  用戶擁有某種角色,從而擁有了對資源的訪問操作權限,在訪問時SpringSecurity會對所有請求進行攔截,有權限的請求放行,否則攔截。

二 SpringBoot使用SpringSecurity

  SpringBoot對SpringSecurity做了支持,要使用的話很方便,只需要引入相應的依賴(spring-boot-starter-security)就可以了。

  示例代碼主要完成以下功能:

  1 系統的首頁和登錄頁面及一些靜態資源(CSS,JS),默認所有用戶都可以訪問;

  2 除了第一步的,其他的所有資源路徑訪問均需要用戶通過認證;

  3 登錄用戶在頁面只能看到擁有的角色所對應的權限(資源或操作);

  修改pom.xml文件,添加依賴

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity4</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

  創建配置類,繼承 WebSecurityConfigurerAdapter,重寫一些配置方法

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

       @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                    .antMatchers("/", "/static/**").permitAll()
                    .anyRequest().authenticated()
                .and().formLogin().loginPage("/login").permitAll()
                    .successForwardUrl("/main")
                    .failureUrl("/login")
                .and().logout()
                    .logoutUrl("/logout").permitAll()
               .logoutSuccessUrl("/login");
    }


}

  @EnableWebSecurity 用來說明開啟安全認證

  configure(HttpSecurity http) 配置相關訪問操作的策略

  .antMatchers("/",  "/static/**").permitAll()  說明項目根路徑/  及static路徑下的靜態資源可以被匿名訪問

  .anyRequest().authenticated()  說明除了可以被匿名訪問的資源外,其他所有資源的訪問都要經過認證

  .formLogin()  說明使用用戶自定義的登錄,如果不配置的話,會使用SpringSecurity默認提供的登錄頁面,/login 資源可以被匿名訪問,登錄成功后訪問/main,失敗后訪問/login

  .logout()  退出功能,SpringSecurity默認對/logout做了監控

  用戶登錄就是對當前用戶的身份信息做認證,我們需要對相應的方法做重寫

@Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
    }

  指定使用自定義的實現用戶認證及授權的userDetailsService和密碼的加密器

  密碼加密器

public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

  認證與授權

@Bean
    @Override
    protected UserDetailsService userDetailsService() {
        return new UserDetailsService(){
            @Override
            public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
                //此處模擬數據庫查詢用戶
                User user = new User();
                user.setUserId(2);
                user.setUsername(username);
                user.setPassword("$2a$10$GS71hBKk0MaykCWZC/eo2e7Y0Z77zDNCYE06xxAmW37gl850E6I4G");
                user.setTelephone("13000000000");
                user.setEmail("13000000000@qq.com");

                if(user == null) throw new UsernameNotFoundException("User name:"+username+" not fount");
                SecurityUser securityUser= new SecurityUser(user);
                return securityUser;
            }
        };
    }
/**
     * 真正用於登錄驗證的安全用戶(UserDetails)
     */
    class SecurityUser extends User implements UserDetails {
        /**
         * 用戶權限
         */
        private Set<SimpleGrantedAuthority> permissions;
        public Set<SimpleGrantedAuthority> getPermissions() {
            return permissions;
        }
        public void setPermissions(Set<SimpleGrantedAuthority> permissions) {
            this.permissions = permissions;
        }

        public SecurityUser(User user){
            if(user != null){
                this.setUserId(user.getUserId());
                this.setUsername(user.getUsername());
                this.setPassword(user.getPassword());
                this.setEmail(user.getEmail());
                this.setTelephone(user.getTelephone());
                Set<SimpleGrantedAuthority> gasSet = (Set<SimpleGrantedAuthority>) getAuthorities();
                if(gasSet.size()>0){
                    this.setPermissions(gasSet);
                }
            }
        }

        /**
         * 獲取用戶權限
         * @return
         */
        @Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
            //要返回的用戶權限集合
            Set<GrantedAuthority> permsSet = new HashSet<GrantedAuthority>();
            //模擬數據庫查詢用戶所擁有的角色對應的權限
            permsSet.add(new SimpleGrantedAuthority("/user/add"));
            permsSet.add(new SimpleGrantedAuthority("/user/edit"));
            permsSet.add(new SimpleGrantedAuthority("/user/delete"));
            permsSet.add(new SimpleGrantedAuthority("/user/list"));

            //區分不同用戶擁有不同權限,admin用戶加權限
            if (this.getUsername().equals("admin")) {
                permsSet.add(new SimpleGrantedAuthority("/role/list"));
                permsSet.add(new SimpleGrantedAuthority("/role/add"));
                permsSet.add(new SimpleGrantedAuthority("/role/edit"));
                permsSet.add(new SimpleGrantedAuthority("/role/delete"));
            }
            return permsSet;
        }

        @Override
        public boolean isAccountNonExpired() {
            return true;
        }

        @Override
        public boolean isAccountNonLocked() {
            return true;
        }

        @Override
        public boolean isCredentialsNonExpired() {
            return true;
        }

        @Override
        public boolean isEnabled() {
            return true;
        }
    }

  控制器

@Controller
public class LoginController {

    /**
     * 訪問根路徑時跳轉到index頁面
     * @return
     */
    @GetMapping("/")
    public String root(){
        return "index";
    }

    /**
     * 跳轉到登錄頁面
     * @return
     */
    @GetMapping("/login")
    public String login(){
        return "login";
    }

    /**
     * 登錄成功后訪問
     * @return
     */
    @PostMapping("/main")
    public String main(){
        return "main";
    }

}

  index頁面

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>index</title>
</head>
<body>
this is index page<br/>
<a th:href="@{/user/login}">登錄</a>
</body>
</html>

  登錄頁面

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>
this is login page
<form th:action="@{/login}" method="post">
    <input type="text" th:id="username" th:name="username" value="" >
    <input type="password" th:id="password" th:name="password" value="">
    <input type="submit" th:value="提交" >
</form>
</body>
</html>

  main頁面

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1 th:text="這是主頁面">text</h1>
<form th:action="@{/logout}" method="post"><button th:type="submit" th:text="退出">text</button></form>
<hr/>

<th:block sec:authorize="hasAuthority('/user/add')">
    <a th:href="@{/user/add}">添加用戶</a>
</th:block>
<th:block sec:authorize="hasAuthority('/user/edit')">
    <a th:href="@{/user/edit}">修改用戶</a>
</th:block>
<th:block sec:authorize="hasAuthority('/user/delete')">
    <a th:href="@{/user/delete}">刪除用戶</a>
</th:block>
<th:block sec:authorize="hasAuthority('/user/list')">
    <a th:href="@{/user/list}">查詢用戶</a>
</th:block>
<th:block sec:authorize="hasAuthority('/role/add')">
        <a th:href="@{/role/add}">添加角色</a>
</th:block>
<th:block sec:authorize="hasAuthority('/role/delete')">
    <a th:href="@{/role/delete}">刪除角色</a>
</th:block>
<th:block sec:authorize="hasAuthority('/role/edit')">
    <a th:href="@{/role/edit}">修改角色</a>
</th:block>
<th:block sec:authorize="hasAuthority('/role/list')">
    <a th:href="@{/role/list}">查詢角色</a>
</th:block>
</body>
</html>

  sec:authorize="hasAuthority('')" 說明當用戶擁有此權限的時候,操作對用戶可見,否則不可見

  分別用user用戶和admin登錄后看到首頁信息

 


免責聲明!

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



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