spring security基本知识(一)

Spring Security是为基于Spring的应用程序提供声明式安全保护的安全 性框架。Spring Security提供了完整的安全性解决方案,它能够在Web 请求级别和方法调用级别处理身份认证和授权。因为基于Spring框 架,所以Spring Security充分利用了依赖注入(dependency injection, DI)和面向切面的技术。Spring Security借助一系列Servlet Filter来提供各种安全性功能。但是这一系列Servlet Filter并不需要我们在web.xml或WebApplicationInitializer中配置多个Filter。

要实现自定义security配置,最核心的就是重写“WebSecurityConfigurerAdapter”。

相关解释说明

注解 @EnableWebSecurity

在 Spring boot 应用中使用 Spring Security,用到了 @EnableWebSecurity注解。

抽象类 WebSecurityConfigurerAdapter

一般情况,会选择继承 WebSecurityConfigurerAdapter 类。WebSecurityConfigurerAdapter 提供了一种便利的方式去创建 WebSecurityConfigurer的实例,只需要重写 WebSecurityConfigurerAdapter 的方法,即可配置拦截什么URL、设置什么权限等安全控制

WebSecurityConfigurerAdapter里的重要方法:

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

2、configure(AuthenticationManagerBuilder)通过重在配置user-detail 服务。

3、configure(WebSecurity)通过重载,配置Spring Security的Filter链

详细说明:

1、 configure(HttpSecurity)

我们知道,在引入security依赖后,启动项目在登陆时就会出现弹窗让我们来输入账号密码。那是因为WebSecurityConfigurerAdapter自身已经实现了一套安全过滤,但这并不是我们想要的。先来看一下WebSecurityConfigurerAdapter的configure(HttpSecurity) 方法如下。HttpSecurity 实现了一个 HttpSecurityBuilder 接口,这是一个构造器接口,因此可以使用构造器典型的链式调用风格.通过调用authorizeRequests()和 anyRequest()。

    @Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated()
.and().formLogin()
.and().httpBasic();
}

我们需要自定义符合我们需求的安全过滤体系,重载后的方法如下。

    /**
* 匹配 "/" 路径,不需要权限即可访问
* 匹配 "/user" 及其以下所有路径,都需要 "USER" 权限
* 登录地址为 "/login",登录成功默认跳转到页面 "/user"
* 退出登录的地址为 "/logout",退出成功后跳转到页面 "/login"
* 默认启用 CSRF
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/user/**").hasRole("USER")
.and().formLogin().loginPage("/login").defaultSuccessUrl("/user")
.and().logout().logoutUrl("/logout").logoutSuccessUrl("/login");
}

当然,HttpSecurity的方法还有很多,比如csrf()、sessionManagement()等,后续再详细说明。

2、configure(AuthenticationManagerBuilder)

Spring Security非常灵活,能够基于各种数据存储来认证用户。它内置了许多常见的用户存储场景。如: 内存,关系型数据库,以及LDAP。当然,我们也可以编写并插入自定义的用户存储实现。

查看AuthenticationManagerBuilder源码,有如下方法:

    public InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> inMemoryAuthentication() throws Exception {
return (InMemoryUserDetailsManagerConfigurer)this.apply(new InMemoryUserDetailsManagerConfigurer());
}//内存 public JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder> jdbcAuthentication() throws Exception {
return (JdbcUserDetailsManagerConfigurer)this.apply(new JdbcUserDetailsManagerConfigurer());
}//jdbc public <T extends UserDetailsService> DaoAuthenticationConfigurer<AuthenticationManagerBuilder, T> userDetailsService(T userDetailsService) throws Exception {
this.defaultUserDetailsService = userDetailsService;
return (DaoAuthenticationConfigurer)this.apply(new DaoAuthenticationConfigurer(userDetailsService));
}//用户自定义 public LdapAuthenticationProviderConfigurer<AuthenticationManagerBuilder> ldapAuthentication() throws Exception {
return (LdapAuthenticationProviderConfigurer)this.apply(new LdapAuthenticationProviderConfigurer());
}//ldap

1)使用基于内存的用户存储

    @Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user_name1").password("123456").roles("USER")
.and()
.withUser("user_name1").password("123456").roles("ADMIN");
}

2)基于JDBC

    @Autowired
private javax.sql.DataSource dataSource; //基于数据库表的用户存储
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource); }

在这里我们只需要配置一个dataSource即可,这样就可以访问关系型数据库了。其中 dataSource是通过自动装配的技巧得到的。在springboot下 dataSource 是自动装配的。我们只需要引入如下依赖

        <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency> <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>

并在appliciation.properties 中配置spring.datasource 相关属性即可。

spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&characterEncoding=utf-8&allowMultiQueries=true
spring.datasource.username=root
spring.datasource.password=root

Spring Boot就会使用该配置创建一个DataSource。并装配为Spring的一个bean。因此我们可以直接使用 @Autowired 进行注入。

好了,直到目前为止,对基于数据库的用户存储已经配置完毕,你可能回想,那既然基于数据库了,肯定要在数据库创建相应的表了。那表结构又是怎么样的呢?

auth.jdbcAuthentication()方法返回的是JdbcUserDetailsManagerConfigurer,他除了dataSource(dataSource)方法还有,

public JdbcUserDetailsManagerConfigurer<B> usersByUsernameQuery(String query) throws Exception {
this.getUserDetailsService().setUsersByUsernameQuery(query);
return this;
} public JdbcUserDetailsManagerConfigurer<B> authoritiesByUsernameQuery(String query) throws Exception {
this.getUserDetailsService().setAuthoritiesByUsernameQuery(query);
return this;
} public JdbcUserDetailsManagerConfigurer<B> groupAuthoritiesByUsername(String query) throws Exception {
JdbcUserDetailsManager userDetailsService = this.getUserDetailsService();
userDetailsService.setEnableGroups(true);
userDetailsService.setGroupAuthoritiesByUsernameQuery(query);
return this;
}

这几个方法。他们在JdbcDaoImpl中有默认的SQL。

private String authoritiesByUsernameQuery = "select username,authority from authorities where username = ?";
private String groupAuthoritiesByUsernameQuery = "select g.id, g.group_name, ga.authority from groups g, group_members gm, group_authorities ga where gm.username = ? and g.id = ga.group_id and g.id = gm.group_id";
private String usersByUsernameQuery = "select username,password,enabled from users where username = ?";

当然我们也可以根据业务自己定义SQL

@Autowired
private DataSource dataSource; //基于数据库表的用户存储
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery("select username,password,enabled,email from users where username=?")
.authoritiesByUsernameQuery("select username,authority from authorities where username = ?")
.groupAuthoritiesByUsername("select g.id, g.group_name, ga.authority from groups g, group_members gm, group_authorities ga where gm.username = ? and g.id = ga.group_id and g.id = gm.group_id");
}

我们就是要依据这些SQL来创建表格,或者可以反过来说。我们定义好表格后使用自定义的SQL。

spring security基本知识(一)的更多相关文章

  1. spring security基本知识(三) 过滤详细说明

    在我们前面的文章Spring Security 初识(一)中,我们看到了一个最简单的 Spring Security 配置,会要求所有的请求都要经过认证.但是,这并不是我们想要的,我们通常想自定义应用 ...

  2. spring security基本知识(二) 自定义认证

    配置自定义的用户存储 我们在 SecurityConfig 的配置类中 重写了 configure(AuthenticationManagerBuilder auth) 方法,我们可以通过 Authe ...

  3. spring security基本知识(四) WebSecurity

    1.创建一个Filter   现在web.xml文档中声明一个filter class="org".springframework.web.filter.DelegatingFil ...

  4. 【Spring】12、Spring Security 四种使用方式

    spring security使用分类: 如何使用spring security,相信百度过的都知道,总共有四种用法,从简到深为:1.不用数据库,全部数据写在配置文件,这个也是官方文档里面的demo: ...

  5. spring security的原理及教程

    spring security使用分类: 如何使用spring security,相信百度过的都知道,总共有四种用法,从简到深为:1.不用数据库,全部数据写在配置文件,这个也是官方文档里面的demo: ...

  6. [转]spring security的原理及教程

    Authentication:认证     spring security使用分类: 如何使用spring security,相信百度过的都知道,总共有四种用法,从简到深为:1.不用数据库,全部数据写 ...

  7. Spring security 知识笔记【自定义登录页面】

    一.引入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...

  8. Spring security 知识笔记【入门】

    一.生成spring boot项目文件 二.pom文件如下 <?xml version="1.0" encoding="UTF-8"?> <p ...

  9. spring security oauth2.0 实现

    oauth应该属于security的一部分.关于oauth的的相关知识可以查看阮一峰的文章:http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html ...

随机推荐

  1. 自定义Spring-Boot @Enable注解

    Spring-Boot中有很多Enable开头的注解,通过添加注解来开启一项功能,如 其原理是什么?如何开发自己的Enable注解? 1.原理 以@EnableScheduling为例,查看其源码,发 ...

  2. LeetCode.1013-分割数组为三个和相同的部分

    这是小川的第378次更新,第406篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第240题(顺位题号是1013).给定一个整数数组A,当且仅当我们可以将数组分成具有相等和 ...

  3. P4878 [USACO05DEC] 布局

    题面lalala 这居然是个紫题???原谅我觉得这题是模板... 这个这个,这题的算法呢其实是一个叫差分约束的东西,也是今天下午我们机房的重点,如果不知道这个差分约束是个啥的人呢,自行百度一下谢谢.. ...

  4. 修改了Mysql密码后连接不到服务且无报错信息解决方法以及修改密码方法

    安装MYSQL后更改了root的密码后用 net start mysql 启动时出现:无法启动,无报错信息 使用以下命令:1.管理员方式cmd进入mysql安装目录的bin目录下2.执行命令:mysq ...

  5. 第六周作业&实验报告四

    一.实验目的 (1)掌握类的继承 (2)变量的继承和覆盖,方法的继承,重载和覆盖的实现: 二.实验的内容 (1)根据下面的要求实现圆类Circle. 1.圆类Circle的成员变量:radius表示圆 ...

  6. AttributeError: 'dict' object has no attribute 'status_code'

    前端AJAX请求数据,提示错误:“AttributeError: 'dict' object has no attribute 'status_code'”. 原因:是提示返回对象dict没有“sta ...

  7. 【Linux 驱动】简单字符设备驱动架构(LED驱动)

    本文基于icool210开发板,内核版本:linux2.6.35: 驱动代码: (1)头文件:led.h #ifndef __LED_H__ #define __LED_H__ #define LED ...

  8. 小记---------手动执行脚本正常执行,使用crontab定时执行时 不执行

    可能出现的原因就是因为crontab不会从用户的/etc/profile文件中读取环境变量,所以就出现 使用定时crontab执行时 无法执行 抛错 所以在使用crontab 定时执行脚本时  在脚本 ...

  9. 并发之AQS原理(二) CLH队列与Node解析

    并发之AQS原理(二) CLH队列与Node解析 1.CLH队列与Node节点 就像通常医院看病排队一样,医生一次能看的病人数量有限,那么超出医生看病速度之外的病人就要排队. 一条队列是队列中每一个人 ...

  10. 【一个蒟蒻的挣扎】LCA (倍增)

    #include<cstdio> #include<iostream> #include<cstring> using namespace std; struct ...