当前位置:   article > 正文

从零搭建若依(Ruoyi-Vue)管理系统(11)--整合Spring Security_若依是如何集成secrity的

若依是如何集成secrity的

本章先按照若依中源码实现的配置和功能进行搭建,后续会有一些改变
本章结束后对应的节选代码文件:Gangbb-Vue-11-SpringSecurity
https://github.com/Gang-bb/Gangbb-Vue
历史遗留TODO:

  • 第四章
  1. 登录日志还未实现。(到登录和权限模块完成)
  2. LogAspect从缓存获取当前的用户信息使用模拟的数据(到登录和权限模块完成)

本章将留下TODO:

  • 第十一章
  1. 需要在Spring Security中注册的登录鉴权逻辑处理类、JWT处理的过滤器、退出登录处理类(到登录和权限模块完成)

本章将解决TODO:

1.添加依赖

Gangbb-commonpom.xml

<dependencies>
	<!-- spring security 安全认证 begin-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <!-- spring security 安全认证 end-->
</dependencies>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2. 添加用户信息

首先要认证就必要要有用户。所以我们新建一个用户表sys_user

CREATE TABLE `sys_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `user_name` varchar(30) NOT NULL COMMENT '用户账号',
  `nick_name` varchar(30) NOT NULL COMMENT '用户昵称',
  `user_type` varchar(2) DEFAULT '00' COMMENT '用户类型(00系统用户)',
  `email` varchar(50) DEFAULT '' COMMENT '用户邮箱',
  `phone_number` varchar(11) DEFAULT '' COMMENT '手机号码',
  `sex` tinyint(4) unsigned DEFAULT '0' COMMENT '用户性别(0男 1女 2未知)',
  `avatar` varchar(150) DEFAULT '' COMMENT '头像地址',
  `password` varchar(100) DEFAULT '' COMMENT '密码',
  `status` tinyint(4) unsigned DEFAULT '0' COMMENT '用户状态 1-启用 2-禁用 3-锁定',
  `del_flag` tinyint(4) unsigned DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
  `login_ip` varchar(50) DEFAULT '' COMMENT '最后登录IP',
  `login_date` datetime DEFAULT NULL COMMENT '最后登录时间',
  `error_count` tinyint(4) unsigned DEFAULT '0' COMMENT '错误次数',
  `creator` varchar(64) DEFAULT '' COMMENT '创建者',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `reviser` varchar(64) DEFAULT '' COMMENT '更新者',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='用户信息表';
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

并在项目中新建对应的SysUserSysUserServiceSysUserMapperSysUserServiceImplSysUserMapper.xml

3. 配置Spring Security

所有配置都在package com.gangbb.core.config.SecurityConfig中。沿用若依的配置(若依中配置文件在package com.ruoyi.framework.config.SecurityConfig)。

关于@EnableGlobalMethodSecurity可以查看上节。

补充1:

Spring Security 中的退出登录

内置 Filter 全解析 我们知道退出登录逻辑是由过滤器 LogoutFilter 来执行的。 它持有三个接口类型的属性:

  1. RequestMatcher: logoutRequestMatcher 这个用来拦截退出请求的 URL
  2. LogoutHandler: handler 用来处理退出的具体逻辑 (若依中只用了这个配置)
  3. LogoutSuccessHandler: logoutSuccessHandler 退出成功后执行的逻辑

我们通过对以上三个接口的实现就能实现我们自定义的退出逻辑.

补充2:

Spring Security 中的异常

Spring Security 中的异常主要分为两大类:一类是认证异常,另一类是授权相关的异常。

AuthenticationException 是在用户认证的时候出现错误时抛出的异常。

Spring Security 中的异常处理

HttpSecurity 提供的exceptionHandling()方法用来提供异常处理。该方法构造出 ExceptionHandlingConfigurer 异常处理配置类。该配置类提供了两个实用接口: AuthenticationEntryPoint 该类用来统一处理 AuthenticationException 异常。 AccessDeniedHandler 该类用来统一处理 AccessDeniedException 异常。

我们只要实现并配置这两个异常处理类即可实现对 Spring Security 认证授权相关的异常进行统一的自定 义处理。

4. 需要添加的功能类

  • 一个继承于AuthenticationEntryPointAuthenticationEntryPointImpl 认证失败处理类。处理类核心就是让Spring Security 验证失败返回一个自定义的ApiRestResponse
package com.ruoyi.framework.security.handle;

import java.io.IOException;
import java.io.Serializable;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;

/**
 * 认证失败处理类 返回未授权
 * 
 * @author ruoyi
 */
@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, Serializable
{
    private static final long serialVersionUID = -8970718410437077606L;

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e)
            throws IOException
    {
        int code = HttpStatus.UNAUTHORIZED;
        String msg = StringUtils.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI());
        ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(code, msg)));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

以下是与登录登出相关的类

(登录鉴权下章开讲)

登录鉴权逻辑处理类:

  • 继承UserDetailsServiceUserDetailsServiceImpl

JWT处理的过滤器:

  • JwtAuthenticationTokenFiltertoken认证过滤器

配合LogoutHandler配置的:

  • LogoutSuccessHandlerImpl退出登录处理类

5. 配置代码

本章结束后的SecurityConfig

package com.gangbb.core.config;


import com.gangbb.core.security.filter.LangFilter;
import com.gangbb.core.security.handle.AuthenticationEntryPointImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * @author : Gangbb
 * @ClassName : SecurityConfig
 * @Description : spring security配置
 * @Date : 2021/3/13 10:52
 */


@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
    @Autowired
    private LangFilter langFilter;

    @Autowired
    private AuthenticationEntryPointImpl authenticationEntryPoint;


    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception
    {
        return super.authenticationManagerBean();
    }

    /** antMatchers()过滤请求中:
     *
     * anyRequest          |   匹配所有请求路径
     * access              |   SpringEl表达式结果为true时可以访问
     * anonymous           |   匿名可以访问
     * denyAll             |   用户不能访问
     * fullyAuthenticated  |   用户完全认证可以访问(非remember-me下自动登录)
     * hasAnyAuthority     |   如果有参数,参数表示权限,则其中任何一个权限可以访问
     * hasAnyRole          |   如果有参数,参数表示角色,则其中任何一个角色可以访问
     * hasAuthority        |   如果有参数,参数表示权限,则其权限可以访问
     * hasIpAddress        |   如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
     * hasRole             |   如果有参数,参数表示角色,则其角色可以访问
     * permitAll           |   用户可以任意访问
     * rememberMe          |   允许通过remember-me登录的用户访问
     * authenticated       |   用户登录后可访问
     */
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception
    {
        httpSecurity
                // CSRF禁用,因为不使用session
                .csrf().disable()
                // 认证失败处理类
                .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).and()
                // 基于token,所以不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                // 过滤请求
                .authorizeRequests()
                // 对于登录login 验证码captchaImage 允许匿名访问
                .antMatchers("/login", "/captchaImage").anonymous()
                .antMatchers(
                        HttpMethod.GET,
                        "/*.html",
                        "/**/*.html",
                        "/**/*.css",
                        "/**/*.js"
                ).permitAll()
                .antMatchers("/profile/**").anonymous()
                .antMatchers("/common/download**").anonymous()
                .antMatchers("/common/download/resource**").anonymous()
                // 本章节中还未集成接口文档swagger
                .antMatchers("/swagger-ui.html").anonymous()
                .antMatchers("/swagger-resources/**").anonymous()
                .antMatchers("/webjars/**").anonymous()
                .antMatchers("/*/api-docs").anonymous()
                .antMatchers("/druid/**").anonymous()
                .antMatchers("/test/**").anonymous()
                // 除上面外的所有请求全部需要鉴权认证
                .anyRequest().authenticated()
                .and()
                // 允许使用内嵌网页iframe(springSecurity 默认使用X-Frame-Options防止网页被Frame)
                .headers().frameOptions().disable();
//                .and()
//                .addFilterBefore(langFilter, BasicAuthenticationFilter.class);
        //httpSecurity.addFilter(langFilter);
        //httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);
        // 添加JWT filter
        //httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
        // 添加CORS filter
        //httpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class);
        //httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class);
    }


    /**
     * 强散列哈希加密实现
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder()
    {
        return new BCryptPasswordEncoder();
    }

    /**
     * 身份认证接口
     */
//    @Override
//    protected void configure(AuthenticationManagerBuilder auth) throws Exception
//    {
//        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
//    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122

6. 测试一些功能

关闭对测试接口的放行:

在这里插入图片描述

请求结果:

在这里插入图片描述

开启对测试接口的放行后:

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/人工智能uu/article/detail/989312
推荐阅读
相关标签
  

闽ICP备14008679号