SpringBoot 集成 SpringSecurity + MySQL + JWT 附源码,废话不多直接盘

这篇具有很好参考价值的文章主要介绍了SpringBoot 集成 SpringSecurity + MySQL + JWT 附源码,废话不多直接盘。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

SpringBoot 集成 SpringSecurity + MySQL + JWT 无太多理论,直接盘
一般用于Web管理系统
可以先看 SpringBoot SpringSecurity 基于内存的使用介绍
本文介绍如何整合 SpringSecurity + MySQL + JWT

数据结构

数据库脚本:https://gitee.com/VipSoft/VipBoot/blob/develop/vipsoft-security/sql/Security.sql
SpringBoot 集成 SpringSecurity + MySQL + JWT 附源码,废话不多直接盘
常规权限管理数据结构设计,三张常规表:用户、角色、菜单,通过用户和角色的关系,角色和菜单(权限)的关系,实现用户和菜单(按钮)的访问控制权

用户登录

  1. SecurityConfig 中添加登录接口匿名访问配置

    .antMatchers("/auth/login", "/captchaImage").anonymous()
    BCryptPasswordEncoder 密码加密方式

  2. POST 登录接口 /auth/login

    调用 AuthorizationController.login 用户登录接口
    做入参、图形验证码等验证。

  3. 实现 UserDetailsService 接口

    根据用户名,去数据库获取用户信息、权限获取等

  4. 密码验证

    AuthorizationService.login
    调用 authenticationManager.authenticate(authenticationToken) 看密码是否正确
    可以在此集合 Redis 做失败次数逻辑处理

  5. 通过JWT 生成 Token

    调用 jwtUtil.generateToken(userId) 生成Token令牌
    将 用户信息放入 Redis
    剔除其它已登录的用户(如果需要)

  6. 返回Map对象给前端

接口权限认证

  1. 获取request.getHeader中的token信息

    AuthenticationTokenFilter.doFilterInternal
    解析 Token 中的用户ID 去 Redis 缓存中获取用户信息
    将信息赋到 SecurityContextHolder.getContext().setAuthentication(authenticationToken) 中,供权限验证获取用户信息使用, SecurityContextHolder使用了ThreadLocal机制来保存每个使用者的安全上下文

  2. 接口权限配置

    UserController 类的方法上,加了 @PreAuthorize("@ps.hasAnyPermi('system:user:list')") 用来做权限控制

  3. 访问权限控制

    PermissionService.hasAnyPermi 判断,用户所拥有的权限,是否包含 @PreAuthorize("@ps.hasAnyPermi('system:user:list')") 中配置的权限,包含则有权访问

用户登录代码

SpringBoot 集成 SpringSecurity + MySQL + JWT 附源码,废话不多直接盘

SecurityConfig

package com.vipsoft.web.config;

import com.vipsoft.web.security.AuthenticationEntryPointImpl;
import com.vipsoft.web.security.AuthenticationTokenFilter;
import com.vipsoft.web.security.LogoutSuccessHandlerImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    /**
     * 自定义用户认证逻辑
     */
    @Autowired
    private UserDetailsService userDetailsService;

    /**
     * 认证失败处理类
     */
    @Autowired
    private AuthenticationEntryPointImpl unauthorizedHandler;


    /**
     * 退出处理类
     */
    @Autowired
    private LogoutSuccessHandlerImpl logoutSuccessHandler;
    /**
     * token认证过滤器
     */
    @Autowired
    private AuthenticationTokenFilter authenticationTokenFilter;



    /**
     * 解决 无法直接注入 AuthenticationManager
     *
     * @return
     * @throws Exception
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    /**
     * 强散列哈希加密实现
     * 必须 Bean 的形式实例化,否则会报 :Encoded password does not look like BCrypt
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder()
    {
        return new BCryptPasswordEncoder();
    }

    /**
     * 配置用户身份的configure()方法
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
    }

    /**
     * 配置用户权限的configure()方法
     *
     * @param httpSecurity
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
                // 禁用 CSRF,因为不使用session
                .csrf().disable()
                // 认证失败处理类
                .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
                // 基于token,所以不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                // 过滤请求
                .authorizeRequests()
                // 对于登录login 验证码captchaImage 允许匿名访问
                .antMatchers("/auth/login", "/captchaImage").anonymous()
                .antMatchers(
                        HttpMethod.GET,
                        "/*.html",
                        "/**/*.html",
                        "/**/*.css",
                        "/**/*.js",
                        "/webSocket/**"
                ).permitAll()
                // swagger 文档
                .antMatchers("/swagger-ui.html").permitAll()
                .antMatchers("/swagger-resources/**").permitAll()
                .antMatchers("/webjars/**").permitAll()
                .antMatchers("/*/api-docs").permitAll()
                .antMatchers("/druid/**").permitAll()
                // 放行OPTIONS请求
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                // 所有请求都需要认证
                .anyRequest().authenticated()
                //        .and().apply(this.securityConfigurerAdapter());

                .and()
                //设置跨域, 如果不设置, 即使配置了filter, 也不会生效
                .cors()
                .and()
                .headers().frameOptions().disable();
        httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);
        // 添加JWT filter
        httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
    }
}

AuthenticationController.login

public Map<String, Object> login(SysUser user) {
    String username = user.getUserName();
    String password = user.getPassword();
    Authentication authentication;
    try {
        //该方法会去调用UserDetailsServiceImpl.loadUserByUsername
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
        authentication = authenticationManager.authenticate(authenticationToken);
    } catch (AuthenticationException ex) {
        Long incr = 3L; // Redis 实现
        if (incr > 5) {
            logger.error("{} 账户连续{}次登录失败,账户被锁定30分钟", username, incr);
            throw new LockedException("密码连续输入错误次数过多,账户已被锁定!");
        }
        throw new BadCredentialsException("您输入的用户名、密码或验证码不正确,为保证账户安全,连续5次输入错误,系统将锁定您的账户30分钟,当前剩余:" + (PASSOWRD_MAX_ERROR_COUNT - incr) + "次", ex);
    }

    SecurityContextHolder.getContext().setAuthentication(authentication);
    LoginUser loginUser = (LoginUser) authentication.getPrincipal();

    String userId = loginUser.getUser().getUserId().toString();
    // 生成令牌
    String token = jwtUtil.generateToken(userId);
    Map<String, Object> resultMap = new HashMap();
    resultMap.put("AccessToken", token);
    resultMap.put("UserId", userId);

    // Redis 保存上线信息
    // UserAgent userAgent
    // 踢掉已登录用户

    return resultMap;
}

UserDetailsServiceImpl


@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private ISysUserService userService;

    @Autowired
    private ISysMenuService menuService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        SysUser user = userService.selectUserByUserName(username);
        if (user == null) {
            logger.info("登录用户:{} 不存在.", username);
            throw new UsernameNotFoundException("登录用户:" + username + " 不存在");
        } else if ("1".equals(user.getDelFlag())) {
            logger.info("登录用户:{} 已被删除.", username);
            throw new CustomException("对不起,您的账号:" + username + " 已被删除");
        } else if ("1".equals(user.getStatus())) {
            logger.info("登录用户:{} 已被停用.", username);
            throw new CustomException("对不起,您的账号:" + username + " 已停用");
        }

        Set<String> perms = new HashSet<>();
        // 管理员拥有所有权限
        if (user.isAdmin()) {
            perms.add("*:*:*");
        } else {
            perms.addAll(menuService.selectMenuPermsByUserId(user.getUserId()));
        }
        return new LoginUser(user, perms);
    }
}

接口权限认证代码

SpringBoot 集成 SpringSecurity + MySQL + JWT 附源码,废话不多直接盘
SpringBoot 集成 SpringSecurity + MySQL + JWT 附源码,废话不多直接盘

AuthenticationTokenFilter

@Component
public class AuthenticationTokenFilter extends OncePerRequestFilter {
    @Autowired
    private JwtUtil jwtUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        LoginUser loginUser = jwtUtil.getLoginUser(request);
        if (loginUser != null && SecurityUtils.getAuthentication() == null) {
            jwtUtil.verifyToken(loginUser);
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            //SecurityContextHolder使用了ThreadLocal机制来保存每个使用者的安全上下文,确保PermissionService判断权限时可以获得当前LoginUser信息
            SecurityUtils.setAuthentication(authenticationToken);
        }
        chain.doFilter(request, response);
    }
}

定义权限验证类 PermissionService

package com.vipsoft.web.security;

import cn.hutool.core.util.StrUtil;
import com.vipsoft.web.utils.SecurityUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.Arrays;
import java.util.Set;

/**
 * 自定义权限实现
 */
@Service("ps")
public class PermissionService {
    /**
     * 所有权限标识
     */
    private static final String ALL_PERMISSION = "*:*:*";

    /**
     * 管理员角色权限标识
     */
    private static final String SUPER_ADMIN = "admin";

    private static final String ROLE_DELIMETER = ",";

    private static final String PERMISSION_DELIMETER = ",";


    /**
     * 对用户请求的接口进行验证,看接口所需要的权限,当前用户是否包括
     *
     * @param permissions 以 PERMISSION_NAMES_DELIMETER 为分隔符的权限列表,如:system:user:add,system:user:edit
     * @return 用户是否具有以下任意一个权限
     */
    public boolean hasAnyPermi(String permissions) {
        if (StrUtil.isEmpty(permissions)) {
            return false;
        }
        LoginUser loginUser = SecurityUtils.getCurrentUser(); //去SecurityContextHolder.getContext()中获取登录用户信息
        if (loginUser == null || CollectionUtils.isEmpty(loginUser.getPermissions())) {
            return false;
        }
        Set<String> authorities = loginUser.getPermissions();
        String[] perms = permissions.split(PERMISSION_DELIMETER);
        boolean hasPerms = Arrays.stream(perms).anyMatch(authorities::contains);
        //是Admin权限 或者 拥有接口所需权限时
        return permissions.contains(ALL_PERMISSION) || hasPerms;
    }
}

SpringBoot 集成 SpringSecurity + MySQL + JWT 附源码,废话不多直接盘
SpringBoot 集成 SpringSecurity + MySQL + JWT 附源码,废话不多直接盘

详细代码见:https://gitee.com/VipSoft/VipBoot/tree/develop/vipsoft-security
源代码摘自:若依后台管理系统文章来源地址https://www.toymoban.com/news/detail-433146.html

到了这里,关于SpringBoot 集成 SpringSecurity + MySQL + JWT 附源码,废话不多直接盘的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【SpringSecurity】十一、SpringSecurity集成JWT实现token的方法与校验

    添加JWT的maven依赖: application.yaml中配置密钥的值,方便代码中引用和后续更改: 这里的命名改为JWTService好点,Utils命名似乎偏静态方法一点。 再贴一下下统一结果类的定义: 下面是安全用户类,用于在数据库的用户对象类SysUser和返给框架的官方对象类UserDetails之间做过渡转

    2024年02月10日
    浏览(42)
  • SpringSecurity实现角色权限控制(SpringBoot+SpringSecurity+JWT)

    通过 springboot整合jwt和security ,以用户名/密码的方式进行认证和授权。认证通过jwt+数据库的,授权这里使用了两种方式,分别是 SpringSecurity自带的hasRole方法+SecurityConfig 和 我们自定义的 permission+@PreAuthorize注解。 SpringSecurity中的几个重要组件: 1.SecurityContextHolder(class) 用来

    2024年02月05日
    浏览(44)
  • 如何使用IDEA创建Servlet程序(不多说一句废话版~)

    说一下现在创建Servlet或Web项目和之前(Eclipse)的主要区别,之前是直接创建,现在是先要创建Java项目,再通过添加支持框架变成Servlet或Web项目。 废话不多说,回归主题,开干: 在创建的空项目的基础上,File-New-Module… Java-Module SDK-Next。 起个模块名-Finish。 鼠标在项目名上

    2023年04月08日
    浏览(78)
  • SpringBoot整合SpringSecurity和JWT

    JWT 1.介绍: 全称 JSON Web Token ,通过数字签名的方式,以 JSON 为载体,在不同的服务终端之间安全的传递信息。 常用于授权认证,用户登录后的每个请求都包含 JWT ,后端处理请求之前都要进行校验。 2.组成: Header :数据头,令牌类型和加密算法 Payload :负载,请求体和其他

    2024年02月03日
    浏览(56)
  • SpringBoot3.0 + SpringSecurity6.0+JWT

    SpringBoot3.0 + SpringSecurity6.0+JWT Spring Security 是 Spring 家族中的一个安全管理框架。 一般Web应用的需要进行 认证 和 授权 。 认证:验证当前访问系统的是不是本系统的用户,并且要确认具体是哪个用户 授权:经过认证后判断当前用户是否有权限进行某个操作 搭建一个SpringBoot工

    2023年04月13日
    浏览(45)
  • springboot+springsecurity+jwt+elementui图书管理系统

    1.1添加pom.xml 1.2创建CodeGenerator代码生成类 1.3生成crontroller、service、mapper、entity等业务实体类 运行CodeGenerator,生成业务实体类 请输入表名,多个英文逗号分割: t_user,t_menu,t_role,t_user_role,t_role_menu 2.1整合springsecurity 1) 2.2认证授权流程 认证管理 流程图解读: 1、用户提交用户名

    2024年02月06日
    浏览(47)
  • SpringBoot集成 SpringSecurity安全框架

    提示:以下是本篇文章正文内容,Java 系列学习将会持续更新 我们时常会在 QQ 上收到别人发送的钓鱼网站链接,只要你在登录QQ账号的情况下点击链接,那么不出意外,你的号已经在别人手中了。实际上这一类网站都属于 恶意网站 ,专门用于盗取他人信息,执行非法操作,

    2024年02月07日
    浏览(49)
  • springboot集成JWT

    Jwt简介 JWT是JSON Web Token的缩写,是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519)。JWT本身没有定义任何技术实现,它只是定义了一种基于Token的会话管理的规则,涵盖Token需要包含的标准内容和Token的生成过程,特别适用于分布式站点的单点登录(SS

    2024年02月09日
    浏览(38)
  • SpringBoot集成JWT token实现权限验证

    先在pom中引入 JWT依赖 然后引入一个生成的 token 的工具类         然后具体实现上有两种方式,一个是使用自定义注解配合拦截器,另外一个是使用拦截器。 方法一:         先自定义个注解,然后再定义一个自定义拦截器 JwtInterceptor 类,同时让 JwtInterceptor 类继承

    2024年02月10日
    浏览(58)
  • SpringBoot集成SpringSecurity从0到1搭建权限管理详细过程(认证+授权)

    最近工作需要给一个老系统搭建一套权限管理,选用的安全框架是SpringSecurity,基本上是结合业务从0到1搭建了一套权限管理,然后想着可以将一些核心逻辑抽取出来写一个权限通用Demo,特此记录下。 Spring Security是 Spring家族中的一个安全管理框架。相比与另外一个安全框架

    2024年02月04日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包