Spring Security(一)(基本介绍及使用)

前言

学习security,记录下

正文

1. 简介

Spring Security是为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了完整的安全性解决方案,可以在Web请求级别和方法调用级别处理身份认证和授权充分利用了Spring IOC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能。

2. 模块
  • ACL 支持通过访问控制列表(access control list,ACl)为域对象提供安全性
  • Aspects 一个很小的模块,当使用Spring Security注解时,会使用基于AspectJ的切面
  • CAS Client 提供与CAS集成的功能
  • Configuration 包含XML和JAVA配置的功能支持
  • Core 基本功能库
  • Cryptography 提供加密和密码编码相关功能
  • LDAP 基于LDAP认证
  • OpenID 支持使用OpenID进行集中式认证
  • Remoting 提供了对Spring Remoting的支持
  • Tag Library Security的JSP标签库
  • Web 提供了Security基于Filter的Wen安全性支持
    备注:
    应用程序的类路径下至少需要包括Core和Configuration模块,Web应用下需要加入Web应用
3. Demo(基于SpringBoot+SpringSecurity+MySql)
3.1. pom.xml
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

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

        <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-devtools</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <executable>true</executable>
                    <fork>true</fork><!--注意要修改这里,支持热部署-->
                </configuration>
            </plugin>
        </plugins>
    </build>
3.2. config

配置类WebSecurityConfig继承WebSecurityConfigurerAdapter

@Configuration
@EnableWebSecurity//启用安全
@EnableGlobalMethodSecurity(securedEnabled = true,jsr250Enabled = true,prePostEnabled = true)//开启注解
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
}

重载configure(HttpSecurity)方法,通过重载,配置如何通过拦截器保护请求

@Override
protected void configure(HttpSecurity http) throws Exception {
             http.formLogin().loginPage("/login").loginProcessingUrl("/auth/login").defaultSuccessUrl("/index")//指定登录页面以及登录成功后的跳转页面
                .and()
                .logout().logoutSuccessUrl("/login")//指定登出后的页面
                .and()
                .authorizeRequests()//拦截请求配置
                .antMatchers("/css/**", "/js/**","/images/**", "/static/**").permitAll()//允许访问静态资源
                .antMatchers("/login","/auth/login").permitAll()  //  premitAll()不做拦截
                .antMatchers("/index").authenticated()   //authenticated()  必须登录后可见
                .antMatchers("/hello").access("hasRole('ADMIN')") //必须拥有ADMIN角色权限才可以访问
                .anyRequest().authenticated();
                //.and()
//              .rememberMe().tokenValiditySeconds(2419200).tokenRepository(persistentTokenRepository()).alwaysRemember(true);// 启用记住我
    }

重载configure(AuthenticationManagerBuilder)方法,通过重载,配置user-detail服务
重载configure(WebSecurity)方法,通过重载,配置Security的Filter链

3.3. 四种用户验证方式

上面提到了重载configure(AuthenticationManagerBuilder)方法,可以配置user-detail服务,这个方法决定用户的校验方式,一般来说有四种

  • 基于内存验证
auth.inMemoryAuthentication()
                  .withUser("admin").password(passwordEncoder().encode("admin")).roles("ADMIN").and()
                      .withUser("test").password(passwordEncoder().encode("test")).roles("TEST");
  • 基于数据库验证
auth.jdbcAuthentication().dataSource(dataSource)
              .usersByUsernameQuery("select username,password,enabled from user where username = ?")
              .authoritiesByUsernameQuery("select username,rolename from role where username=?")
              .passwordEncoder(passwordEncoder());
  • 基于LDAP验证
auth.ldapAuthentication().userSearchFilter("{uid=0}").groupSearchFilter("member={0}");
  • 自定义用户服务
auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());

这里customUserDetailsService必须实现UserDetailsService

@Component
@Slf4j
public class CustomUserDetailsService implements UserDetailsService {
    @Autowired
    private UserRepository userRepository;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByAccount(username);
        if (user==null){
            throw new AuthenticationCredentialsNotFoundException("authError");
        }
        Set<Role> roles = user.getRoles();
        List<GrantedAuthority> authorities = new ArrayList<>();
        roles.forEach(role-> authorities.addAll(AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_"+role.getName())));
        return new org.springframework.security.core.userdetails.User(user.getAccount(),user.getPassword(),authorities);
    }
}
3.4. 注解

三种不同的安全注解

  • 自带的@Secured注解(@EnableGlobalMethodSecurity中设置securedEnabled = true)
  • JSR-250的@RolesAllowed注解(@EnableGlobalMethodSecurity中设置jsr250Enabled = true)
  • 表达式驱动注解,@PreAuthorize、@PostAuthorize、@PreFilter、@PostFilter
    这里我们主要讲表达式驱动注解:
    @PreAuthorize 方法调用之前,基于表达式的计算结果来限制对方法的访问
    @PostAuthorize 方法调用之后,如果表达式的结果为false,则抛出异常
    @PreFilter 方法调用之前,过滤进入方法的输入值
    @PostFilter 方法调用之后,过滤方法的结果值
@Controller
@RequestMapping("/")
public class AuthController {

    @GetMapping("login")
    public String login (){
        return "login";
    }
    @GetMapping("index")
    public String index(){
        return "index";
    }
    @GetMapping("hello")
    @PreAuthorize("hasRole('ADMIN')")
    public String hello(){//必须拥有ADMIN权限的用户才可以进去
        return "hello";
    }
    @GetMapping("postAuth")
    @PostAuthorize("hasRole('TEST')")
    @ResponseBody
    public String  postAuth(){//可以进入但是没有TEST的权限的用户会报403错误
        return "postAuth";
    }
    @PostMapping("preFilter")
    @PreFilter(filterTarget="users", value="filterObject.id != null")
    @ResponseBody
    public String  preFilter(@RequestBody List<User> users){//进入方法后users的size为0
        return "preFilter";
    }
    @PostMapping("postFilter")
    @PostFilter(value="filterObject.id != null")
    @ResponseBody
    public List<User> postFilter(@RequestBody User user){//客户端拿到的是空的
        List<User> users = new ArrayList<User>();
        users.add(user);
        return users;
    }
}

总结

一些基本的功能以及介绍已经了解了,具体的使用还是需要投入到实际项目中,下面接着往下学习。
security是如何进行登录验证和权限控制的?

参考资料
参考代码

demo 地址

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352

推荐阅读更多精彩内容