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. prism 4 模块配置 管理

    本章导读: 第四章讲述了模块化应用程序开发中模块的生命周期,生成方法,实例引用的存活时间等关键内容,和经常会应用到的包含定义模块在内的7种场景(以Unity为例,也说明了MEF与Unity中可能不同的 ...

  2. svn版本合并

    假如你的项目(这里指的是手机客户端项目)的某个版本(例如1.0版本)已经完成开发.测试并已经上线了,接下来接到新的需求,新需求的开发需要修改多个文件中的代码,当需求已经开始开发一段时间的时候,突然接到 ...

  3. Flutter异步Future

    一.认识Future 1.创建Future void testFuture(){ Future future = new Future(() => null); future.then((_){ ...

  4. 搜索框的测试checklist

    一:简单搜索输入框测试用例1:不输入任何字符,点击搜索按钮,一般搜索出网站所有的信息 2:一般搜索输入框中的有文章显示,当鼠标点击时,文章消失 3:输入全角/半角中文字符(一个字符.超长字符.已经信息 ...

  5. (转)GIS中的4D产品(DLG、DRG、DEM、DOM)

    DLG 数字线划地图(DLG, Digital Line Graphic):是与现有线划基本一致的各地图要素的矢量 数据集,且保存各要素间的空间关系和相关的属性信息. 在世字测图中,最为常见的产品就是 ...

  6. vue --》路由query 编程式导航传值与监听

    1.首先在一个页面设置一个按钮,用于路由跳转 <template> <div> <button @click="handleToRouter"> ...

  7. python 并发编程 多线程 event

    event实现了一个线程通知另外一个线程 线程的一个关键特性是每个线程都是独立运行且状态不可预测. 1.为什么要使用Event对象: 如果程序中的其 他线程需要通过判断某个线程的状态来确定自己下一步的 ...

  8. css精灵图使用

    1. 精灵技术的使用 CSS 精灵其实是将网页中的一些背景图像整合到一张大图中(精灵图),然而,各个网页元素通常只需要精灵图中不同位置的某个小图,要想精确定位到精灵图中的某个小图,就需要使用CSS的b ...

  9. Python细节(二)小数据池

    3.8小数据池 python是由代码块构成的 代码块,一个模块.一个函数,一个类,一个文件,eval(),exec()执行的时候也是一个代码块 1.内存地址 id() 通过id() 我们可以查看到一个 ...

  10. 普通交叉验证(OCV)和广义交叉验证(GCV)

    普通交叉验证OCV OCV是由Allen(1974)在回归背景下提出的,之后Wahba和Wold(1975)在讨论 了确定多项式回归中多项式次数的背景,在光滑样条背景下提出OCV. Craven和Wa ...