【Spring Security】一、入门

1.Spring Security简介

  Spring Security的前身是Acegi Security,在被收纳为Spring 子项目后正式更名为 Spring Security。
  Spring Security 可以帮助开发者更便捷的完成  认证 + 授权
  认证:确认某主体在系统中是否合法、可用
  授权:即主体通过认证之后,是否允许执行某项操作的过程。

2.Spring Security项目

在Springboot中添加以下依赖

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

或者引入spring-security-webspring-security-config
两个核心模块,此时声明最简单的hello路由

@RestController
@SpringBootApplication
public class Demo1Application {
    @GetMapping("/hello")
    public String hello(){
        return "hello";
    }

    public static void main(String[] args) {
        SpringApplication.run(Demo1Application.class, args);
    }

}

虽然没有进行任何配置,但是Springboot会自动进行配置,在WebSecurityConfigurerAdapter中配置默认运行状态。
需要在进行HTTP表单验证之后才能访问URL资源

启动项目时就会默认在控制台输出密码

2020-08-12 21:45:34.951  INFO 6948 --- [  restartedMain] .s.s.UserDetailsServiceAutoConfiguration : 
Using generated security password: da4d7e67-5311-46a0-b03a-4476f4ff157a

application.properties中自定义配置账户与密码

spring.security.user.name=user
spring.security.user.password=123

在Spring Security 4.x版本中默认的登录方式是HTTP验证,即用户名、密码在弹窗中完成,但是安全性差、无法携带cookie,
所以后来的默认配置是 HTTP表单认证。

3.表单认证

3.1.默认表单认证

查看WebSecurityConfigurerAdapter 中的configure方法

protected void configure(HttpSecurity http) throws Exception {
        this.logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity).");
        ((HttpSecurity)((HttpSecurity)((AuthorizedUrl)http.
            authorizeRequests(). 
            anyRequest()).   //所有请求
            authenticated().and()). 
            formLogin().and()). //允许进行表单登录进行身份验证
            httpBasic(); //允许用户使用http基本认证
}

3.2自定义表单验证

  • 3.2.1 创建配置类 继承WebSecurityConfigurerAdapter类
  • 3.2.2 使用@EnbableWebSecurity注解
  • 3.2.3 重写configure(HttpSecurity http)方法
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    ((HttpSecurity)((HttpSecurity)((ExpressionUrlAuthorizationConfigurer.AuthorizedUrl)http.
        authorizeRequests().

        anyRequest()).   //所有请求  如果是外置的css 与 js 需要修改 否则静态资源也会被拦截
        authenticated().and()).
        formLogin().loginPage("/myLogin.html").permitAll().//自定义登陆页面  登录页不设限访问
            and()). 
        csrf().disable();//关闭 跨站请求伪造防护功能
        }
}
   <form class="form"  action="myLogin.html" method="post">
	<input type="text" placeholder="用户名" id="username" name="username" >
	<input type="password" placeholder="密码" id="password" name="password">
	<button type="submit">登录</button>
  </form>
  • 3.2.4 编写自定义登录页 myLogin.html
    Spring Security 会为 myLogin.html 生成一个POST路由用于接受登录请求

表单其他配置项

  • loginProcessingUrl 指定登录请求路径例如指定为 /login 则form表单中 action = "login"
  • successHandler 指定登录成功的逻辑
  • failureHandler 指定登陆失败的逻辑

3.3认识HttpSecurity对象

HttpSecurity对象其实对应着 Spring Security 命名空间配置方式中的XML文件标签,为特定的HTTP请求配置安全策略。

HttpSecurity 如果是使用Java默认的传统方式配置会相当复杂,所以被设计成了链式调用
每个方法执行完之后都会返回一个预期的上下文,便于连续调用。

HttpSecurity提供了很多方法,分别对应命名空间中的标签,例如
authorizeRequests-><intercept-url>
formLogin-><form-login>
httpBasic-><http-basic>
除非使用and()方法结束当前标签,上下文才会回到HttpSecurity。

<?xml version="1.0" encoding="UTF-8"?>
<bean:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:bean="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.1.xsd">

    <!--
    1、设置放行资源,如登录注册页面,静态资源css、js等等
        security="none" 设置此资源不被拦截.
    -->
    <http pattern="/login.html" security="none"></http>
    <http pattern="/loginerror.html" security="none"></http>
    <http pattern="/css/**" security="none"></http>
    <http pattern="/img/**" security="none"></http>
    <http pattern="/js/**" security="none"></http>
    <http pattern="/plugins/**" security="none"></http>

    <http>
        <!-- 2、拦截所有(除放行资源外) -->
        <intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
        <!-- 
            3、登录表单设置
            1)login-page:指定登录页面;
            2)login-processing-url:指定登录请求路径;

            3)default-target-url:指定了成功进行身份验证和授权后默认呈现给用户的页面;
            4)always-use-default-target:指定了是否在身份验证通过后总是跳转到; 
                                       default-target-url 属性指定的 URL。
            5)authentication-failure-url:指定了身份验证失败时跳转到的页面;                           
         -->
        <form-login login-page="/login.html" 
                    login-processing-url="/login"
                    always-use-default-target="true" 
                    default-target-url="/admin/index.html"
                    authentication-failure-url="/loginerror.html"

                     />
        <!--   4、注销设置
                  1)logout-url:指定注销的url;
                  2)logout-success-url:注销成功后登录返回的页面。
        -->         
        <logout logout-url="/logout" logout-success-url="/login.html"/>          
        <!-- 
            5、跨站请求设置(我们这里关闭)
               1)csrf disabled="true" 关闭 csrf ,如果不加会出现错误

               2)CSRF(Cross-site request forgery):跨站请求伪造,
                 也被称为“One Click Attack”或者 SessionRiding,
                 通常缩写为 CSRF 或者 XSRF,是一种对网站的恶意利用。
         -->            
        <csrf disabled="true" />

        <!-- 6、iframe 框架结构展示 -->
        <headers>
            <frame-options policy="SAMEORIGIN" />
        </headers>
    </http>
     <!-- 
             认证管理器
             1)我们这里设置一个默认用户
      -->
    <authentication-manager>
        <authentication-provider>
            <user-service>
                <user authorities="ROLE_USER" name="admin" password="123456" />
            </user-service>
        </authentication-provider>
    </authentication-manager>
</bean:beans>

4.认证与授权

基于Spring Security提供默认的用户可能无法满足系统设计的需求。
与Shiro相同 Spring Security 也支持:
首先简单配置url与可以访问的角色

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        ((HttpSecurity)((HttpSecurity)((ExpressionUrlAuthorizationConfigurer.AuthorizedUrl)http.
                authorizeRequests().
                antMatchers("/admin/**").hasRole("ADMIN").
                antMatchers("/user/**").hasRole("USER").
                anyRequest()).   //所有请求  如果是内置的css 与 js 需要修改 否则静态资源也会被拦截
                authenticated().
                and()).
                formLogin().//自定义登陆页面  登录页不设限访问
                and()).
                csrf().disable();//关闭 跨站请求伪造防护功能
    }
}

1.内存中配置用户、角色信息

1.1 使用UserDetailsService接口

@Bean
    public UserDetailsService userDetailsService(){
        InMemoryUserDetailsManager im = new InMemoryUserDetailsManager();
        im.createUser(User.withUsername("user2").password("user2").roles("USER").build());
        im.createUser(User.withUsername("admin2").password("admin2").roles("ADMIN").build());
        return im;
    }      

1.2 实现WebSecurityConfigurerAdapter

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth)throws Exception  {
        auth.inMemoryAuthentication().
                withUser("user").password("{noop}user").roles("USER").and().
                withUser("admin").password("{noop}admin").roles("ADMIN");
    }
}

2.在数据库中配置用户、角色信息

2.1使用默认数据库表

使用JdbcUserDetailsManager,与内存中存储用户UserDetailsService 没有区别。默认使用的数据库模型在
/org/springframework/security/core/userdetails/jdbc/users.ddl

2.2使用自定义数据库表

自定义数据库表需要包含UserDetail中一系列在验证时会用到的信息,自定义实体实现UserDetails接口

package org.springframework.security.core.userdetails;

import java.io.Serializable;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;

public interface UserDetails extends Serializable {
    Collection<? extends GrantedAuthority> getAuthorities();

    String getPassword();

    String getUsername();

    boolean isAccountNonExpired();

    boolean isAccountNonLocked();

    boolean isCredentialsNonExpired();

    boolean isEnabled();
}

实现UserDetailsService接口,重写loadUserByUsername方法,使用Dao操作返回 UserDetails 的实现类对象即可

public interface UserDetailsService {
    UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}
posted @ 2020-08-12 23:17  ShinyRou  阅读(186)  评论(0编辑  收藏  举报