美文网首页探索Spring
Spring Security介绍

Spring Security介绍

作者: Real_man | 来源:发表于2019-10-13 22:06 被阅读0次

    Spring Security是Spring提供的一个安全框架,提供认证和授权功能,最主要的是它提供了简单的使用方式,同时又有很高的灵活性,简单,灵活,强大。

    基础

    SecurityContextHolder,SecurityContext,Authentication是Spring Security的基础对象。

    • SecurityContextHolder:存储当前的SecurityContext,即认证用户的上下文信息,内部使用ThreadLocal。
    • SecurityContext:持有Authentication对象和其他可能需要的信息
    • UserDetails:从Authentication中获取的对象,代表当前用户的具体信息
    • UserDetailsService:获取UserDetails的逻辑,一般封装了查询用户的逻辑,内部只有一个方法:
      • .UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
    • GrantedAuthority:当前用户获取到的授权信息。

    在应用中获取当前用户信息:

    Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    
    if (principal instanceof UserDetails) {
        String username = ((UserDetails)principal).getUsername();
    } else {
        String username = principal.toString();
    }
    

    案例

    1 Spring Boot项目中引入Spring Security的依赖包

    <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    

    2 配置SpringSecurity的安全信息

    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        // @formatter:off
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .authorizeRequests()
                        .antMatchers("/css/**", "/index").permitAll()
                        
                        // 只有USER权限的角色才能访问/user/接口
                        .antMatchers("/user/**").hasRole("USER")
                        .and()
                    .formLogin().loginPage("/login").failureUrl("/login-error");
        }
    
    //  @Autowired
    //  public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    //      auth
    //          .inMemoryAuthentication()
    //              .withUser(User.withDefaultPasswordEncoder().username("user").password("password").roles("USER"));
    //  }
        // @formatter:on
    
        // 密码明文
        @Bean
        public PasswordEncoder passwordEncoder() {
            PasswordEncoder encoder = NoOpPasswordEncoder.getInstance();
            return encoder;
        }
    
    
      // 获取用户的来源
        @Bean
        public UserDetailsService userDetailsService(){
            UserDetailsService userDetailsService = new UserDetailsService(){
    
                @Override
                public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
                    if (StringUtils.isEmpty(username) || !"admin".equalsIgnoreCase(username)){
                        return null;
                    }
    
                    HashSet<GrantedAuthority> hashSet = new HashSet<>();
                    // 内部检验权限,要以ROLE为前缀
                    hashSet.add(new  SimpleGrantedAuthority("ROLE_USER") );
                    User user = new User("admin","test",hashSet);
    
                    return user;
                }
            };
            return userDetailsService;
        }
    }
    
    

    3 编写接口类

    @Controller
    public class MainController {
    
        @RequestMapping("/")
        public String root() {
            return "redirect:/index";
        }
    
        @ResponseBody
        @RequestMapping("/index")
        public String index() {
            return "当前为未经安全认证的页面";
        }
    
        @ResponseBody
        @RequestMapping("/user/index")
        public String userIndex() {
            SecurityContext securityContext = SecurityContextHolder.getContext();
            
            return "user/index";
        }
    
        @RequestMapping("/login")
        public String login() {
            return "login";
        }
    
        @ResponseBody
        @RequestMapping("/login-error")
        public String loginError(Model model) {
    //      model.addAttribute("loginError", true);
            return "login-error";
        }
    
    }
    

    4 登录页面

    // 位置 src/main/resources/templates/login.html
    
    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
        <head>
            <title>Login page</title>
            <meta charset="utf-8" />
            <link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
        </head>
        <body>
            <h1>Login page</h1>
            <p>Example user: user / password</p>
            <p th:if="${loginError}" class="error">Wrong user or password</p>
            <form th:action="@{/login}" method="post">
                <label for="username">Username</label>:
                <input type="text" id="username" name="username" autofocus="autofocus" /> <br />
                <label for="password">Password</label>:
                <input type="password" id="password" name="password" /> <br />
                <input type="submit" value="Log in" />
            </form>
            <p><a href="/index" th:href="@{/index}">Back to home page</a></p>
        </body>
    </html>
    

    5 效果。

    • 当直接访问/user/index页面的时候会因为安全配置重定向到login页面
    • 我们的UserService只配置了admin/test的用户,只有用admin用户才能登录成功
    • 登录成功之后再访问/user/index页面才生效

    6 如果想要测试授权功能,在userDetailsService中返回结果去掉ROLE_USER权限即可。

    调试关键点

    org.springframework.security.access.vote.AffirmativeBased#decide 判断用户是否有权访问当前接口

    org.springframework.security.authentication.dao.DaoAuthenticationProvider#additionalAuthenticationChecks 密码加密校验

    最后

    本文简单介绍了Spring Security的基础内容,给了一个简单的案例,自行运行查看效果

    相关文章

      网友评论

        本文标题:Spring Security介绍

        本文链接:https://www.haomeiwen.com/subject/trnkmctx.html