(二)Spring Security 快速上手

Spring Security介绍

Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。由于它是Spring生态系统中的一员,因此它伴随着整个Spring生态系统不断修正、升级,在spring boot项目中加入springsecurity更是十分简单,使用Spring Security 减少了为企业系统安全控制编写大量重复代码的工作。

创建工程

创建maven工程 security-spring-security,工程结构如下:
(二)Spring Security 快速上手_第1张图片

引入以下依赖:


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>

    <groupId>org.cyjgroupId>
    <artifactId>security-spring-securityartifactId>
    <version>1.0-SNAPSHOTversion>
    <packaging>warpackaging>

    <properties>
        <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
        <maven.compiler.source>1.8maven.compiler.source>
        <maven.compiler.target>1.8maven.compiler.target>
    properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.securitygroupId>
            <artifactId>spring-security-webartifactId>
            <version>5.1.4.RELEASEversion>
        dependency>
        <dependency>
            <groupId>org.springframework.securitygroupId>
            <artifactId>spring-security-configartifactId>
            <version>5.1.4.RELEASEversion>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-webmvcartifactId>
            <version>5.1.5.RELEASEversion>
        dependency>
        <dependency>
            <groupId>javax.servletgroupId>
            <artifactId>javax.servlet-apiartifactId>
            <version>3.0.1version>
            <scope>providedscope>
        dependency>
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <version>1.16.14version>
        dependency>
    dependencies>

    <build>
        <finalName>security-springs-ecuristyfinalName>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.tomcat.mavengroupId>
                    <artifactId>tomcat7-maven-pluginartifactId>
                    <version>2.2version>
                plugin>
                <plugin>
                    <groupId>org.apache.maven.pluginsgroupId>
                    <artifactId>maven-compiler-pluginartifactId>
                    <configuration>
                        <source>1.8source>
                        <target>1.8target>
                    configuration>
                plugin>

                <plugin>
                    <artifactId>maven-resources-pluginartifactId>
                    <configuration>
                        <encoding>utf-8encoding>
                        <useDefaultDelimiters>trueuseDefaultDelimiters>
                        <resources>
                            <resource>
                                <directory>src/main/resourcesdirectory>
                                <filtering>truefiltering>
                                <includes>
                                    <include>**/*include>
                                includes>
                            resource>
                            <resource>
                                <directory>src/main/javadirectory>
                                <includes>
                                    <include>**/*.xmlinclude>
                                includes>
                            resource>
                        resources>
                    configuration>
                plugin>
            plugins>
        pluginManagement>
    build>


project>

Spring容器配置

package com.cyj.security.springsecurity.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;

/**
 * @program: Spring-Security-OAuth2
 * @Description:
 * @Author C_Y_J
 * @create: 2021-01-28 19:14
 **/
@Configuration
@ComponentScan(basePackages = "com.cyj.security.springsecurity",
        excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class)})
public class ApplicationConfig {
    //在此配置除了Controller的其它bean,比如:数据库链接池、事务管理器、业务bean等。
}

Servlet Context配置

package com.cyj.security.springsecurity.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

/**
 * @program: Spring-Security-OAuth2
 * @Description:
 * @Author C_Y_J
 * @create: 2021-01-28 19:15
 **/
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.cyj.security.springsecurity",
        includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class)})
public class WebConfig implements WebMvcConfigurer {

    /**
     * 视频解析器
     *
     * @return
     */
    @Bean
    public InternalResourceViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/view/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("redirect:/login");
    }

}

加载 Spring容器

在init包下定义Spring容器初始化类SpringApplicationInitializer,此类实现WebApplicationInitializer接口,Spring容器启动时加载WebApplicationInitializer接口的所有实现类。

package com.cyj.security.springsecurity.init;

import com.cyj.security.springsecurity.config.ApplicationConfig;
import com.cyj.security.springsecurity.config.WebConfig;
import com.cyj.security.springsecurity.config.WebSecurityConfig;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

/**
 * @program: Spring-Security-OAuth2
 * @Description:
 * @Author C_Y_J
 * @create: 2021-01-28 19:20
 **/
public class SpringApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    /**
     * spring容器,相当于加载 applicationContext.xml
     *
     * @return
     */
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{ApplicationConfig.class};
    }

    /**
     * servletContext,相当于加载springmvc.xml
     *
     * @return
     */
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{WebConfig.class};
    }

    /**
     * url-mapping
     *
     * @return
     */
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

认证

springSecurity默认提供认证页面,不需要额外开发。

(二)Spring Security 快速上手_第2张图片

安全配置

spring security提供了用户名密码登录、退出、会话管理等认证功能,只需要配置即可使用。
(一)在config包下定义WebSecurityConfig,安全配置的内容包括:用户信息、密码编码器、安全拦截机制。

package com.cyj.security.springsecurity.config;

import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

/**
 * @program: Spring-Security-OAuth2
 * @Description:
 * @Author C_Y_J
 * @create: 2021-01-28 19:16
 **/
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 定义用户信息服务(查询用户信息)
     *
     * @return
     */
    @Bean
    @Override
    public UserDetailsService userDetailsService() {
        //暂时使用内存查询
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("zhangsan").password("123").authorities("p1").build());
        manager.createUser(User.withUsername("lisi").password("456").authorities("p2").build());
        return manager;
    }

    /**
     * 密码编码器
     *
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

    /**
     * 安全拦截机制(最重要)
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/r/r1").hasAuthority("p1")
                .antMatchers("/r/r2").hasAuthority("p2")
                //所有/r/**的请求必须认证通过
                .antMatchers("/r/**").authenticated()
                //除了/r/**,其它的请求可以访问
                .anyRequest().permitAll();
        http
                //允许表单登录
                .formLogin()
                //自定义登录成功的页面地址
                .successForwardUrl("/login-success");
    }
}

在userDetailsService()方法中,我们返回了一个UserDetailsService给spring容器,Spring Security会使用它来获取用户信息。我们暂时使用InMemoryUserDetailsManager实现类,并在其中分别创建了zhangsan、lisi两个用户,并设置密码和权限。

而在configure()中,我们通过HttpSecurity设置了安全拦截规则,其中包含了以下内容:
(1)url匹配/r/**的资源,经过认证后才能访问。
(2)其他url完全开放。
(3)支持form表单认证,认证成功后转向/login-success。

(二) 加载 WebSecurityConfig
修改SpringApplicationInitializer的getRootConfigClasses()方法,添加WebSecurityConfig.class:

    /**
     * spring容器,相当于加载 applicationContext.xml
     *
     * @return
     */
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{ApplicationConfig.class, WebSecurityConfig.class};
    }

Spring Security初始化

Spring Security初始化,这里有两种情况
若当前环境没有使用Spring或Spring MVC,则需要将 WebSecurityConfig(Spring Security配置类) 传入超类,以确保获取配置,并创建spring context。

相反,若当前环境已经使用spring,我们应该在现有的springContext中注册Spring Security(上一步已经做将WebSecurityConfig加载至rootcontext),此方法可以什么都不做。

在init包下定义SpringSecurityApplicationInitializer:

public class SpringSecurityApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
    public SpringSecurityApplicationInitializer() {
        //super(WebSecurityConfig.class);
    }
}

默认根路径请求

在WebConfig.java中添加默认请求根路径跳转到/login,此url为spring security提供:

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("redirect:/login");
    }

认证成功页面

在安全配置中,认证成功将跳转到/login-success,代码如下:

    /**
     * 安全拦截机制(最重要)
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/r/r1").hasAuthority("p1")
                .antMatchers("/r/r2").hasAuthority("p2")
                //所有/r/**的请求必须认证通过
                .antMatchers("/r/**").authenticated()
                //除了/r/**,其它的请求可以访问
                .anyRequest().permitAll();
        http
                //允许表单登录
                .formLogin()
                //自定义登录成功的页面地址
                .successForwardUrl("/login-success");

    }

spring security支持form表单认证,认证成功后转向/login-success。在LoginController中定义/login-success:

package com.cyj.security.springsecurity.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @program: Spring-Security-OAuth2
 * @Description:
 * @Author C_Y_J
 * @create: 2021-01-28 19:38
 **/
@RestController
public class LoginController {
    @RequestMapping(value = "/login-success", produces = {"text/plain;charset=utf-8"})
    public String loginSuccess() {
        return " 登录成功";
    }

    @GetMapping(value = "/r/r1", produces = {"text/plain;charset=UTF-8"})
    public String r1() {
        return " 访问资源1";
    }

    @GetMapping(value = "/r/r2", produces = {"text/plain;charset=UTF-8"})
    public String r2() {
        return " 访问资源2";
    }

}

测试

(1)启动项目,访问 http://localhost:8080/security-spring-security 路径地址
(二)Spring Security 快速上手_第3张图片
(二)Spring Security 快速上手_第4张图片

页面会根据WebConfig中addViewControllers配置规则,跳转至/login,/login是pring Security提供的登录页面。
(2)登录
1、输入错误的用户名、密码
(二)Spring Security 快速上手_第5张图片

2、输入正确的用户名、密码,登录成功
在这里插入图片描述

(3)退出
1、请求/logout退出
http://localhost:8080/security-spring-security/logout
(二)Spring Security 快速上手_第6张图片

退出 后再访问资源自动跳转到登录页面

授权

实现授权需要对用户的访问进行拦截校验,校验用户的权限是否可以操作指定的资源,Spring Security默认提供授权实现方法。在LoginController添加/r/r1或/r/r2

    @GetMapping(value = "/r/r1", produces = {"text/plain;charset=UTF-8"})
    public String r1() {
        return " 访问资源1";
    }

    @GetMapping(value = "/r/r2", produces = {"text/plain;charset=UTF-8"})
    public String r2() {
        return " 访问资源2";
    }

在安全配置类WebSecurityConfig.java中配置授权规则:

    /**
     * 安全拦截机制(最重要)
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/r/r1").hasAuthority("p1")
                .antMatchers("/r/r2").hasAuthority("p2")
                //所有/r/**的请求必须认证通过
                .antMatchers("/r/**").authenticated()
                //除了/r/**,其它的请求可以访问
                .anyRequest().permitAll();
        http
                //允许表单登录
                .formLogin()
                //自定义登录成功的页面地址
                .successForwardUrl("/login-success");

    }

.antMatchers("/r/r1").hasAuthority(“p1”)表示:访问/r/r1资源的 url需要拥有p1权限。
.antMatchers("/r/r2").hasAuthority(“p2”)表示:访问/r/r2资源的 url需要拥有p2权限。
测试:
1、登录成功
2、访问/r/r1和/r/r2,有权限时则正常访问,否则返回403(拒绝访问)

小结

通过快速上手,咱们使用Spring Security实现了认证和授权,Spring Security提供了基于账号和密码的认证方式,通过安全配置即可实现请求拦截,授权功能,Spring Security能完成的不仅仅是这些。

原文链接

你可能感兴趣的:(安全框架)