• 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登录后看到首页信息

  • 相关阅读:
    Linux的概念与体系
    Python快速教程
    Qt控件精讲一:按钮
    xml2-config not found
    Ubuntu 12.04更新源
    Adaboost的几个人脸检测网站
    关于matlab矩阵卷积conv2和傅里叶变换求卷积ifft2的关系
    char数组和String互转
    STL中vector的赋值,遍历,查找,删除,自定义排序——sort,push_back,find,erase
    《离散数学》-图论6.7
  • 原文地址:https://www.cnblogs.com/love-wzy/p/10407550.html
Copyright © 2020-2023  润新知