开发者

Spring Security注解方式权限控制过程

目录
  • 一、摘要
  • 二、实现步骤
    • 2.1 在配置类中添加权限注解的支持
    • 2.2 创建Controller类
    • 2.3 UserService类
  • 三、测试
    • 3.1 user测试
    • 3.2 admin 测试
  • 四、退出登录功能
    • 总结

      一、摘要

      Spring Security除了可以在配置文件中配置权限校验规则,还可以使用注解方式控制类 中方法的调用。

      例如Controller中的某个方法要求必须具有某个权限才可以访问,此时就 可以使用Spring Security框架提供的注解方式进行控制。

      二、实现步骤

      2.1 在配置类中添加权限注解的支持

      Spring Security注解方式权限控制过程

      package com.by.config;
      
      //import com.by.service.UserService;
      import com.by.service.UserService;
      import org.springframework.beans.factory.annotation.Autowired;
      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.WebSecurityConfigurerAdapter;
      import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
      import org.springframework.security.crypto.password.PasswordEncoder;
      
      /**
       * spring security 核心配置
       */
      @Configuration
      @EnableGlobalMethodSecurity(prePostEnabled = true)//开启权限注解支持
      public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        @Autowired
        private UserService userService;
        @Autowired
        private PasswordEncoder passwordEncoder;
          /**
           * 配置认证信息的来源
           * AuthenticationManagerBuilder认证管理器
           */
          @Override
          protected void configure(AuthenticationManagerBuilder auth) throws Exception {
              // 配置认证提供者
              auth.userDetailsService(userService).passwordEncoder(passwordEncoder);//配置认证提供者
              super.configure(auth);//密码
          }
      
          /**
           * 配置web的安全(忽略的静态资源)
           *
           * @param web
           * @throws Exception
           */
          @Override
          public void configure(WebSecurity web) throws Exception {
              //web.ignoring().antMatchers("/pages/a.html","/pages/b.html");
               //web.ignoring().antMatchers("/pages/**");
              //指定login.html页面可以匿名访问
              web.ignoring().antMatchers("/login.html");
          }
      
          /**
           * 配置HTTP请求的安全(认证、授权、退出)
           * HttpSecurity 用于构建一个安全过滤器链 SecurityFilterChain
           *
           * @param http
           * @throws Exception
           */
          @Override
          protected void configure(HttpSecurity http) throws Exception {
      //        super.configure(http);
              http.formLogin()
                      .loginPage("/login.html")// 默认页面
                      .loginProcessingUrl("/login")//请求
                      .usernameParameter("username")
                      .passwordParameter("password")
                      // 请求成功后访问哪个路径
                      .defaultSuccessUrl("/index.html",true);
              //权限配置
              http.authorizeRequests()
                     //.antMatchers("pages/a.html").authenticated()
                      .antMatchers("/pages/b.html").hasAuthority("add")
                      /**
                       * 拥有ROLE_ADMIN可以访问d页面
                       * 注意:此处虽然写的是ADMIN,但是框架会自动添加前缀ROLE_
                       */
                      .antMatchers("pages/c.html").hasRole("ADMIN")
      //                其他资源均需要登录后访问
                      .anyRequest().authenticated();
      //        super.configure(http);
              //关闭跨站请求防护
              http.csrf().disable();
          }
      
          /**
           * 配置加密对象
           * @return
           */
          @Bean
          public PasswordEncoder passwordEncoder(){
              return new BCryptPasswordEncoder();
          }
      }

      2.2 创建Controller类

      在Controller的方法上加入注解进行权限控制

      package com.by.controller;
      
      import org.springframework.security.Access.prepost.PreAuthorize;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      
      @RestController
      @RequestMapping("/hello")
      public class HelloController {
          @RequestMapping("/add")
          /**
           * 表示用户要拥有add权限 才能访问该方法
           */
          @PreAuthorize("hasAuthority('add')")
          public String add(){
              System.out.println("add");
              return "success";
          }
      
      }

      2.3 UserService类

      Spring Security注解方式权限控制过程

      package com.by.service;
      www.devze.com
      import com.by.pojo.UserInfo;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.security.core.GrantedAuthority;
      import org.springframework.security.core.authority.SimpleGrantedAuthority;
      import org.springframework.security.core.userdetails.User;
      import org.springframework.security.core.userdetails.UserDetails;
      import org.springframework.security.core.userdetails.UserDetailsService;
      import org.springframework.security.core.userdetails.UsernameNotFoundException;
      import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
      import org.springframework.security.crypto.password.PasswordEncoder;
      import org.springframework.stereotype.Component;
      
      import Java.util.ArrayList;
      import java.util.HashMap;
      import java.util.List;
      import java.util.Map;
      
      @Component
      public class UserService implements UserDetailsService {
          @Autowired
         private PasswordEncoder passwordEncoder;
      
      
          //模拟向数据库中插入数据
          public Map<String, UserInfo> map = new HashMap<>();
      
          public void init() {
              UserInfo u1 = new UserInfo();
              u1.setUsername("admin");
              u1.setPassword(passwordEncoder.encode("123"));
              UserInfo u2 = new UserInfo();
              u2.setUsername("user");
              u2.setPassword(passwordEncoder.encode("123"));
              map.put(u1.getUsername(), u1);
              map.put(u2.getUsername(), u2);
          }
      
          @Override
          public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
              init();
              System.out.println("username:" + username);
              //模拟从数据库中查询用户
           javascript   UserInfo userInfo = map.get(username);
              if (userInfo == null) {
                  return null;
              }
              //模拟查询数据库中用户的密码  去掉明文标识{noop}
              String password = userInfo.getPassword();
              List<GrantedAuthority> list = new ArrayList<>();
              //授权,后期需要改为查询数据库动态获得用户拥有的权限和角色
              if (username.equals("admin")) {
                  list.add(new SimpleGrantedAuthority("add"));
                  list.add(new SimpleGrantedAuthority("delete"));
              }
              list.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
              User user = new User(username, password, list);
              return user;
          }
      
          public static void main(String[] args) {
              for (int i = 0; i < 3; i++) {
                  String password="123456";
                  /**
                   * BCryptPasswordEncoder是Spring Security
                   * 提供的一个加密的API
                   */
                  BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
                  String hashPassWord = bCryptPasswordEncoder.encode(password);
                  System.out.println(hashPassWord);
                  boolean flag = bCryptPasswordEncoder.matches("123456", hashPassWord);
                  System.out.println(flag);
      
              }
          }
      }

      三、测试

      可以看出admin有add方法的访问权限,而user则没有add方法的访问权限

      3.1 user测试

      Spring Security注解方式权限控制过程

      3.2 admin 测试

      Spring Security注解方式权限控制过程

      四、退出登录功能

      用户完成登录后Spring Security框架会记录当前用户认证状态为已认证状态,即表示用 户登录成功了。

      那用户如何退出登录呢?我们可以配置类中进行如下 配置:

      Spring Security注解方式权限控制过程

      package com.by.config;
      
      //import com.by.service.UserService;
      import com.by.service.UserService;
      import org.springframework.beans.factory.annotation.Autowired;
      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.WebSecurityConfigurerAdapter;
      import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
      import org.springframework.security.crypto.password.PasswordEncoder;
      
      /**
       * spring security 核心配置
       */
      @Configuration
      @EnjsableGlobalMethodSecurity(prePostEnabled = true)//开启权限注解支持
      public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        @Autowired
        private UserService userService;
        @Autowired
        private PasswordEncoder passwordEncoder;
          /**
           * 配置认证信息的来源
           * AuthenticationManagerBuilder认证管理器
           */
          @Override
          protected void configure(AuthenticationManagerBuilder auth) throws Exception {
              // 配置认证提供者
              auth.userDetailsService(userService).passwordEncoder(passwordEncoder);js//配置认证提供者
              super.configure(auth);//密码
          }
      
          /**
           * 配置web的安全(忽略的静态资源)
           *
           * @param web
           * @throws Exception
           */
          @Override
          public void configure(WebSecurity web) throws Exception {
              //web.ignoring().antMatchers("/pages/a.html","/pages/b.html");
               //web.ignoring().antMatchers("/pages/**");
              //指定login.html页面可以匿名访问
              web.ignoring().antMatchers("/login.html");
          }
      
          /**
           * 配置HTTP请求的安全(认证、授权、退出)
           * HttpSecurity 用于构建一个安全过滤器链 SecurityFilterChain
           *
           * @param http
           * @throws Exception
           */
          @Override
          编程protected void configure(HttpSecurity http) throws Exception {
      //        super.configure(http);
              http.formLogin()
                      .loginPage("/login.html")// 默认页面
                      .loginProcessingUrl("/login")//请求
                      .usernameParameter("username")
                      .passwordParameter("password")
                      // 请求成功后访问哪个路径
                      .defaultSuccessUrl("/index.html",true);
              //权限配置
              http.authorizeRequests()
                     //.antMatchers("pages/a.html").authenticated()
                      .antMatchers("/pages/b.html").hasAuthority("add")
                      /**
                       * 拥有ROLE_ADMIN可以访问d页面
                       * 注意:此处虽然写的是ADMIN,但是框架会自动添加前缀ROLE_
                       */
                      .antMatchers("pages/c.html").hasRole("ADMIN")
      //                其他资源均需要登录后访问
                      .anyRequest().authenticated();
              /**
               * 退出登录
               */
              http.logout()
                      .logoutUrl("/logout")
                              .logoutSuccessUrl("/login.html").invalidateHttpSession(true);
      
      
      
      //        super.configure(http);
              //关闭跨站请求防护
              http.csrf().disable();
          }
      
          /**
           * 配置加密对象
           * @return
           */
          @Bean
          public PasswordEncoder passwordEncoder(){
              return new BCryptPasswordEncoder();
          }
      }

      在a.html 设置一个退出登录的超链接

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
      </head>
      <body>
      我是b.html
      <a href="/logout" rel="external nofollow" >退出登录</a>
      </body>
      </html>

      测试

      登录后访问localhost:8083/pages/a.html 然后点击退出登录。

      Spring Security注解方式权限控制过程

      Spring Security注解方式权限控制过程

      如果用户要退出登录,只需要请求/logout这个URL地址就 可以,最后页面会跳转到login.html页面

      总结

      以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

      0

      上一篇:

      下一篇:

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      最新开发

      开发排行榜