Spring Security修炼手册(一)————初识Security

Stella981
• 阅读 573

    在以前做东西的时候,对于认证鉴权的框架技术选型,通常使用Apache Shiro,可能是接触比较早,感觉用起来比较方便的原因,知道最近接了一个好大好大的项目分布式应用+大数据数据库+私有IaaS云+PaaS,埋头苦学一星期,算是吃透了Spring Security的一半,那么一是为了记录在学习过程中的知识点,二是为了让没有接触过安全框架,或者还在使用数据库,自己写Filter比较原始方式做权限控制的朋友提供一个学习的参考。那么废话不说太多,下面开始一步一步来。

  一、初识Spring Security

        首先看名字就可以看出来,这个框架出自于Pivotal 的Spring系列。Spring Security 提供了基于javaEE的企业应用,全面的安全服务。 大家使用Spring Secruity的原因有很多,但是大部分都是发现了由于javaEE的Servlet规范或EJB规范中的安全功能缺乏典型企业应用场景所需的深度。 那么Security提供的 “认证”和“授权”(或者访问控制) 是整个框架也是本系列博客所要讲解的重要内容。

二、引入Security依赖

    Security官方链接:https://projects.spring.io/spring-security/

    打开你的IED,在Maven坐标如下:想使用其他版本请去如上链接,如果你之前接触过Spring IO那么无需指定Version.

<dependencies>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-web</artifactId>
        <version>5.0.5.RELEASE</version>
    </dependency>
</dependencies>

  Gradle如下:

dependencies {
    compile 'org.springframework.security:spring-security-web:5.0.5.RELEASE'
}

三、Security的基本认证功能的使用

    首先明确一个事情,Spring Security所有提供给开发者的认证和鉴权功能都是基于过滤器链的,而我看到的大部分讲解Security的博客和资料中,却很少提及每个功能作用的过滤器是谁?过滤器的执行流程是怎么样的!我之前在学习Docker和K8S的时候买的一本书讲解的非常透彻,作者不仅仅在讲怎么用!而是从:是什么?怎么用?为什么?这三方面来说,因此我会在文中通过Debug或流程图,为大家深入的讲解这款框架的东西。

    3.1、HttpBasic认证

        那么当你引入了Security的依赖后,无需做其他任何的事情,启动项目,访问的时候你就会发现你的应用已经有了一个基本的认证功能,其实前面说的话不是完全正确的,由于笔者之前使用的Spring Boot版本为1.5,依赖的Security 4.X版本,所以无需任何配置,启动项目访问则会弹出默认的httpbasic认证,那么本次Demo是基于security5.X ,Spring Boot2.X版本去做的,经过我翻阅官方文档和Spring Boot2.X的properties,在这个5.X的版本中已经将默认的认证方式更改为表单认证,并且security.basic.enabled属性同样是过期了的。

                                        Spring Security修炼手册(一)————初识Security

下面的图是官方给出的属性配置,已经无security.basic.enabled

    Spring Security修炼手册(一)————初识Security

        在这里笔者十分负责任的说,如果想开启httpbasic认证,需要在配置类中进行配置才可以,亲测通过properties配置不生效,开启httpbasic认证的代码如下:

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        
        http
           .httpBasic()//开启httpbasic认证
        .and()
           .authorizeRequests()//Security表达式
                 .anyRequest().authenticated();//所有请求都需要认证
    }

}

    启动项目,在启动的时候会发现控制台有如下输出,这个字符串就是Security默认生成的认证密码。

Spring Security修炼手册(一)————初识Security

    访问应用,弹出httpbasic,通过生成的默认密码进行认证,不过这种方式基本不太会使用,不着重介绍。

Spring Security修炼手册(一)————初识Security

    3.2、表单认证

        表单认证是大部分业务场景中都需要使用的一种认证方式,那么如何配置,又有哪些可配置的呢?看如下代码:

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurer
Adapter;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{
    
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        
        http
        .formLogin()
            .loginPage("/loginPage.html")//用户未认证时,转跳到认证的页面
            .loginProcessingUrl("/toLogin")//form中action的地址,也就是处理认证请求的URL    
            .usernameParameter("UM")//form中用户名密码的name名
            .passwordParameter("PW")
            .defaultSuccessUrl("/index")//认证成功后默认转跳的URL
        .and()
        .authorizeRequests()
            .antMatchers("/loginPage.html","/toLogin").permitAll()//最后不要忘记将自定义的
                                                                           //如上不需要认证的URL加进来
            .anyRequest().authenticated();
    }

}

我们访问任意需要认证的URL,发现会自动转跳到配置的认证页面。

Spring Security修炼手册(一)————初识Security

 我们暂时先使用内存用户,在properties中配置一个admin用户,模拟登录。

Spring Security修炼手册(一)————初识Security

 登陆后,自动转跳到index的controller中,对了!如果你使用了自己的登录页面,记得将CSRF防护功能关掉哦,否则你讲无法进行认证。

Spring Security修炼手册(一)————初识Security

四、基于Spring的配置

    那么通过以上代码的讲解,你应该对于认证功能的基本使用有了一定的了解,但是上面的代码中有一个开发界非常难以容忍的问题,就是含有大量的硬编码!!!那么我们如何解决的?

Spring Security修炼手册(一)————初识Security

首先我们创建三个类,分别叫:SecurityProperties、ToLoginProperties、LoginProperties,代码分别如下:

public class LoginProperties {
    
    private String loginPage = "/loginPage.html";
    
    private String loginProcessingUrl = "/toLogin";
    
    private String usernameParameter = "UM";
    
    private String passwordParameter = "PW";
    
    private String defaultSuccessUrl = "/index";

    public String getLoginPage() {
        return loginPage;
    }

    public void setLoginPage(String loginPage) {
        this.loginPage = loginPage;
    }

    public String getLoginProcessingUrl() {
        return loginProcessingUrl;
    }

    public void setLoginProcessingUrl(String loginProcessingUrl) {
        this.loginProcessingUrl = loginProcessingUrl;
    }

    public String getUsernameParameter() {
        return usernameParameter;
    }

    public void setUsernameParameter(String usernameParameter) {
        this.usernameParameter = usernameParameter;
    }

    public String getPasswordParameter() {
        return passwordParameter;
    }

    public void setPasswordParameter(String passwordParameter) {
        this.passwordParameter = passwordParameter;
    }

    public String getDefaultSuccessUrl() {
        return defaultSuccessUrl;
    }

    public void setDefaultSuccessUrl(String defaultSuccessUrl) {
        this.defaultSuccessUrl = defaultSuccessUrl;
    }
    
    
}


public class ToLoginProperties {
    
    private LoginProperties loginProperties = new LoginProperties();

    public LoginProperties getLoginProperties() {
        return loginProperties;
    }

    public void setLoginProperties(LoginProperties loginProperties) {
        this.loginProperties = loginProperties;
    }

}


import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "jy.security")
public class SecurityProperties {

    private ToLoginProperties toLoginProperties = new ToLoginProperties();

    public ToLoginProperties getToLoginProperties() {
        return toLoginProperties;
    }

    public void setToLoginProperties(ToLoginProperties toLoginProperties) {
        this.toLoginProperties = toLoginProperties;
    }
    
}

通过以上代码,我们就可以读取到配置文件中,以“jy.security”开头的属性,并将属性对应的值注入到其中,这样当我们配置了对应属性的时候,值即被替换,未配置的时候则走我们的默认值。

然后我们把securityconfig类在修改一下,不在使用硬编码,而是将SecurityProperties类注入。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

import com.spring.demo.peoperties.SecurityProperties;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{
    
    @Autowired
    private SecurityProperties securityProperties;
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        
        http
            .formLogin()
                .loginPage(securityProperties.getToLoginProperties().getLoginProperties().getLoginPage())//用户未认证时,转跳到认证的页面
                .loginProcessingUrl(securityProperties.getToLoginProperties().getLoginProperties().getLoginProcessingUrl())//form中action的地址,也就是处理认证请求的URL    
                .usernameParameter(securityProperties.getToLoginProperties().getLoginProperties().getUsernameParameter())//form中用户名密码的name名
                .passwordParameter(securityProperties.getToLoginProperties().getLoginProperties().getPasswordParameter())
                .defaultSuccessUrl(securityProperties.getToLoginProperties().getLoginProperties().getDefaultSuccessUrl())//认证成功后默认转跳的URL
        .and()
        .authorizeRequests()
            .antMatchers(securityProperties.getToLoginProperties().getLoginProperties().getLoginPage(),
                         securityProperties.getToLoginProperties().getLoginProperties().getLoginProcessingUrl()).permitAll()
            .anyRequest().authenticated()
        .and()
            .csrf().disable()
            ;
    }
    
    

}

    最后我们做一个测试,证明通过配置文件的方式,可以对我们的配置类修改,我们修改未认证时转跳的认证页面的URL为“/loginTest”

Spring Security修炼手册(一)————初识Security

重启项目,访问/index,结果如下:404是由于我根本没写这个页面,但已经可以证明我们的配置生效,避免了硬编码的问题

Spring Security修炼手册(一)————初识Security

 在下一篇博客里,我会介绍自定义身份认证和一些处理器的用法及源码,敬请关注!

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
java将前端的json数组字符串转换为列表
记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
9个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这