美文网首页
spring security简单学习

spring security简单学习

作者: 丰极 | 来源:发表于2018-10-18 17:53 被阅读0次

    一、初识SpringSecurity

    在springboot项目中加入spring security。

    1、在pom.xml中加入依赖

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

    2、启动

    在启动信息里面有一个自动生成的密码,默认用户名是user。

    2018-10-18 15:31:10.241  INFO 4996 --- [           main] .s.s.UserDetailsServiceAutoConfiguration : 
    
    Using generated security password: dd6f7b68-7409-4195-b908-b78cc9ec92af
    
    

    此时我们就可以用user:dd6f7b68-7409-4195-b908-b78cc9ec92af登录了。

    3、自己配置用户名密码

    在application.yml中加入自定义配置

    spring:
      security:
        user:
          name: admin
          password: admin
    

    此时用户名密码就被定义成admin:admin了。

    4、自定义配置类

    更进一步,上面的安全模式只能有一个用户名密码,我们写一个自定义的配置类,配置多个用户名密码。

    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.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.crypto.password.NoOpPasswordEncoder;
    
    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            super.configure(http);
        }
        
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth
                .inMemoryAuthentication()
                .withUser("user")
                .password("user")
                .roles("USER")
                .and()
                .withUser("admin")
                .password("admin")
                .roles("ADMIN")
                .and()
                .withUser("zhangsan")
                .password("123456")
                .roles("ADMIN");
        }
        
        @Bean
        public static NoOpPasswordEncoder passwordEncoder() {
            return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
        }
    }
    
    @EnableWebSecurity注解开启Spring Security的功能
    @EnableGlobalMethodSecurity(prePostEnabled = true)这个注解,可以开启security的注解,我们可以在需要控制权限的方法上面使用@PreAuthorize,@PreFilter这些注解
    

    在configure(HttpSecurity http)方法里面,默认的认证代码是:

    http
        .authorizeRequests()
        .anyRequest().authenticated()
        .and()
        .formLogin()
        .and()
        .httpBasic();
    
    
    NoOpPasswordEncoder:springboot默认对密码会解析,加上这个是保持用户输入的密码
    

    5、权限的简单使用

    我们可以在方法上加上权限注解,如下:

    import org.springframework.security.access.prepost.PreAuthorize;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class HomeController {
    
        @RequestMapping("/home")
        @PreAuthorize("hasRole('ADMIN')")
        public  String  home() {
            return "hello world";
        }
    }
    

    常用权限

    表达式 描述
    hasRole([role]) 当前用户是否拥有指定角色。
    hasAnyRole([role1,role2]) 多个角色是一个以逗号进行分隔的字符串。如果当前用户拥有指定角色中的任意一个则返回true。
    hasAuthority([auth]) 等同于hasRole
    hasAnyAuthority([auth1,auth2]) 等同于hasAnyRole
    Principle 代表当前用户的principle对象
    authentication 直接从SecurityContext获取的当前Authentication对象
    permitAll 总是返回true,表示允许所有的
    denyAll 总是返回false,表示拒绝所有的
    isAnonymous() 当前用户是否是一个匿名用户
    isRememberMe() 表示当前用户是否是通过Remember-Me自动登录的
    isAuthenticated() 表示当前用户是否已经登录认证成功了。
    isFullyAuthenticated() 如果当前用户既不是一个匿名用户,同时又不是通过Remember-Me自动登录的,则返回true。

    二、进阶 Security

    用数据库存储用户和角色,实现安全认证。

    1、先定义一个user:

    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.userdetails.UserDetails;
    import java.util.Collection;
    
    public class User implements UserDetails {
        private String username;
        private String password;
        private Collection<? extends GrantedAuthority> roles;
    
        public Collection<? extends GrantedAuthority> getRoles() {
            return roles;
        }
        public void setRoles(Collection<? extends GrantedAuthority> roles) {
            this.roles = roles;
        }
        public void setUsername(String username) {
            this.username = username;
        }
        public void setPassword(String password) {
            this.password = password;
        }
        @Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
            return roles;
        }
        @Override
        public String getPassword() {
            return password;
        }
        @Override
        public String getUsername() {
            return username;
        }
        @Override
        public boolean isAccountNonExpired() {
            return true;
        }
        @Override
        public boolean isAccountNonLocked() {
            return true;
        }
        @Override
        public boolean isCredentialsNonExpired() {
            return true;
        }
        @Override
        public boolean isEnabled() {
            return true;
        }
    }
    

    2、定义一个service:

    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import java.util.ArrayList;
    import java.util.List;
    
    public class MyUserDetailsServiceimp implements UserDetailsService {
        @Override
        public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
            List<SimpleGrantedAuthority> list = new ArrayList<>();
            list.add(new SimpleGrantedAuthority("ROLE_ADMIN")); 
            // ROLE默认是带ROLE_开头
            User user = new User();
            user.setUsername(s);
            user.setPassword(s);
            user.setRoles(list);
            return user;
        }
    }
    
    我们只定义了用户名,密码,角色列表,
    其他的账号过期,账号上锁,凭证过期,是否可用都默认设置为true,暂时不考虑。
    
    实际使用的时候是根据username去数据库查询记录,
    在根据的userid查询role,
    并根据记录设置相关的账号过期,上锁等情况。
    

    3、修改我们的配置类

    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            super.configure(http);
        }
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(getUserDetailService());
        }
    
        @Bean
        public static NoOpPasswordEncoder passwordEncoder() {
            return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
        }
    
        @Bean
        public UserDetailsService getUserDetailService() {
            return new MyUserDetailsServiceimp();
        }
    }
    

    用户密码角色的获取从UserDetailService获取。

    4、不拦截的页面

    有些页面我们不想拦截,所有人都能访问,这时候只需要修改我们的配置类就行了:

    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable();
    
            http.authorizeRequests()
                    .antMatchers("/").permitAll()
                    .antMatchers("/plugins/**",
                            "/css/**",
                            "/fonts/**",
                            "/js/**",
                            "/home1",
                            "/home2"
                    ).permitAll() //默认不拦截静态资源的url pattern (2)
                    .anyRequest().authenticated().and()
                    .formLogin()
                    //.loginPage("/login")// 登录url请求路径 (3)
                    //.defaultSuccessUrl("/httpapi").permitAll()
                    .and() // 登录成功跳转路径url(4)
                    .logout().permitAll();
    
            http.logout().logoutSuccessUrl("/"); // 退出默认跳转页面 (5)
        }
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(getUserDetailService());
        }
    
        @Bean
        public static NoOpPasswordEncoder passwordEncoder() {
            return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
        }
    
        @Bean
        public UserDetailsService getUserDetailService() {
            return new MyUserDetailsServiceimp();
        }
    }
    
    如上所示,css,js,font不拦截,/根不拦截,/home1, /home2不拦截
    还可以自定义登录页面,以及登录成功之后的跳转页面
    

    我们看一下此时的homecontroller

    @RestController
    public class HomeController {
        @RequestMapping("/")
        public  String  index() {
            return "hello index!";
        }
        @RequestMapping("/home")
        public  String  home() {
            return "hello home";
        }
        @RequestMapping("/home1")
        public  String  home1() {
            return "hello home1";
        }
        @RequestMapping("/home2")
        public  String  home2() {
            return "hello home2";
        }
    }
    

    5、session

    spring security默认帮我们管理session,我们改下controller,如下:

    @RestController
    public class HomeController {
    
        @RequestMapping("/")
        public  String  index() {
            return "hello index!";
        }
    
        @RequestMapping("/home")
        @PreAuthorize("hasRole('ADMIN')")
        public  String  home() {
            Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            String username = "";
            if (principal instanceof UserDetails) {
                username = ((UserDetails)principal).getUsername();
            } else {
                username = principal.toString();
            }
            System.out.println(username);
            return "hello home";
        }
    
        @RequestMapping("/home1")
        public  String  home1() {
            Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            String username = "";
            if (principal instanceof UserDetails) {
                username = ((UserDetails)principal).getUsername();
            } else {
                username = principal.toString();
            }
            System.out.println(username);
            return "hello home1";
        }
    }
    

    启动服务,我们一次访问:

    http://localhost:8080/home1
    http://localhost:8080/home
    http://localhost:8080/home1
    

    控制台打印如下:

    anonymousUser
    zhangsan
    zhangsan
    

    相关文章

      网友评论

          本文标题:spring security简单学习

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