• SpringSecurity+jwt使用


    参考文章链接

    自定义SpringSecurity用户

    package com.daben.springsecurityjwt.vo;
    
    import com.daben.springsecurityjwt.entity.SysUser;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.userdetails.User;
    import java.util.Collection;
    /**
     * SpringSecurity用户
     *
     * @Author JinDongSheng
     * @Date 2023-11-16 09:21
     */
    public class SpringSecurityUser extends User {
        /**
         * 系统用户
         */
        private SysUser sysUser;
        /**
         * 构造函数
         */
        public SpringSecurityUser(SysUser sysUser, Collection<? extends GrantedAuthority> authorities) {
            super(sysUser.getUsername(), sysUser.getPassword(), authorities);
            this.sysUser = sysUser;
        }
        public SysUser getSysUser() {
            return sysUser;
        }
        public void setSysUser(SysUser sysUser) {
            this.sysUser = sysUser;
        }
    }
    
    • 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

    自定义认证失败处理类

    package com.daben.springsecurityjwt.handle;
    
    import com.alibaba.fastjson2.JSON;
    import com.daben.springsecurityjwt.vo.Result;
    import org.springframework.security.core.AuthenticationException;
    import org.springframework.security.web.AuthenticationEntryPoint;
    import org.springframework.stereotype.Component;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    /**
     * 未登录处理类
     *
     * @Author JinDongSheng
     * @Date 2023-11-15 17:37
     */
    @Component
    public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {
        @Override
        public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
            response.setStatus(200);
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            response.getWriter().print(JSON.toJSONString(Result.error("认证失败,无法访问系统资源!")));
        }
    }
    
    • 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

    自定义Security用户服务实现类

    package com.daben.springsecurityjwt.service;
    
    import com.daben.springsecurityjwt.entity.SysUser;
    import com.daben.springsecurityjwt.vo.SpringSecurityUser;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import org.springframework.stereotype.Service;
    import java.util.Collections;
    /**
     * Security用户服务实现类
     *
     * @Author JinDongSheng
     * @Date 2023-11-16 09:14
     */
    @Service
    public class UserDetailsServiceImpl implements UserDetailsService {
        @Autowired
        private SysUserServiceImpl sysUserServiceImpl;
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            // 根据用户名称查询用户
            SysUser sysUser = sysUserServiceImpl.selectSysUserByName(username);
            // 查询用户权限
            List<GrantedAuthority> authorities = Collections.emptyList();
            // 返回Security指定的用户对象
            return new SpringSecurityUser(sysUser, authorities);
        }
    }
    
    • 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

    自定义JWT工具类

    package com.daben.springsecurityjwt.utils;
    
    import cn.hutool.core.date.DateUtil;
    import cn.hutool.json.JSONUtil;
    import com.daben.springsecurityjwt.entity.SysUser;
    import io.jsonwebtoken.*;
    import org.apache.commons.lang3.StringUtils;
    import java.util.Date;
    /**
     * JWT工具类
     *
     * @Author JinDongSheng
     * @Date 2023-11-16 15:49
     */
    public class JwtUtil {
        /**
         * Token有效期为30分钟
         */
        public static final int EXPIRE_TIME = 30;
        /**
         * 秘钥
         */
        private final static String SECRET_KEY = "ABCDE";
        /**
         * 生成token
         */
        public static String createToken(SysUser user) {
            return Jwts.builder()
                    // 将user放进JWT
                    .setSubject(JSONUtil.toJsonStr(user))
                    // 设置过期时间
                    .setExpiration(DateUtil.offsetMinute(new Date(), EXPIRE_TIME))
                    // 设置加密算法和秘钥
                    .signWith(SignatureAlgorithm.HS512, SECRET_KEY)
                    .compact();
        }
        public static Claims parseToken(String token) {
            // 如果是空字符串直接返回null
            if (StringUtils.isEmpty(token)) {
                return null;
            }
            // 这个Claims对象包含了许多属性,比如签发时间、过期时间以及存放的数据等
            Claims claims = null;
            // 解析失败了会抛出异常,所以我们要捕捉一下。token过期、token非法都会导致解析失败
            try {
                claims = Jwts.parser()
                        .setSigningKey(SECRET_KEY) // 设置秘钥
                        .parseClaimsJws(token)
                        .getBody();
            } catch (JwtException e) {
                // 这里应该用日志输出,为了演示方便就直接打印了
                System.err.println("解析失败!");
            }
            return claims;
        }
    }
    
    • 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

    自定义token认证过滤器

    package com.daben.springsecurityjwt.filter;
    
    import cn.hutool.json.JSONUtil;
    import com.daben.springsecurityjwt.entity.SysUser;
    import com.daben.springsecurityjwt.utils.JwtUtil;
    import io.jsonwebtoken.Claims;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.stereotype.Component;
    import org.springframework.web.filter.OncePerRequestFilter;
    import javax.servlet.FilterChain;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.Collections;
    /**
     * 登录过滤器
     *
     * @Author JinDongSheng
     * @Date 2023-11-16 14:48
     */
    @Component
    public class LoginFilter extends OncePerRequestFilter {
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
            // 解析token
            Claims claims = JwtUtil.parseToken(request.getHeader("Authorization"));
            if (claims != null) {
                // 获取用户
                SysUser sysUser = JSONUtil.toBean(claims.getSubject(), SysUser.class);
                // 手动组装一个认证对象
                Authentication authentication = new UsernamePasswordAuthenticationToken(sysUser, null, Collections.emptyList());
                // 将认证对象放到上下文中
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
            filterChain.doFilter(request, response);
        }
    }
    
    • 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

    自定义SpringSecurity配置类

    package com.daben.springsecurityjwt.config;
    
    import com.daben.springsecurityjwt.filter.LoginFilter;
    import com.daben.springsecurityjwt.handle.AuthenticationEntryPointImpl;
    import com.daben.springsecurityjwt.service.UserDetailsServiceImpl;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    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.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
    /**
     * spring security 配置
     *
     * @Author JinDongSheng
     * @Date 2023-11-15 17:16
     */
    @EnableWebSecurity
    public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
        /**
         * 登录认证过滤器
         */
        @Autowired
        private LoginFilter loginFilter;
        /**
         * Security用户服务实现类
         */
        @Autowired
        private UserDetailsServiceImpl userDetailsService;
        /**
         * 未登录处理类
         */
        @Autowired
        private AuthenticationEntryPointImpl authenticationEntryPoint;
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            // 关闭csrf
            http.csrf().disable();
            // 关闭frameOptions
            http.headers().frameOptions().disable();
            // 指定未登录处理类
            http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
            // 前置登录认证过滤器
            http.addFilterBefore(loginFilter, UsernamePasswordAuthenticationFilter.class);
            // 禁用session
            http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
            // 配置认证和授权接口
            http.authorizeRequests()
                    // 指出放行接口
                    .antMatchers("/sys/port/*").permitAll()
                    // 拦截剩余接口
                    .anyRequest().authenticated();
        }
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            // 指定UserDetailService和加密器
            auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
        }
        @Bean
        @Override
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }
        @Bean
        public PasswordEncoder passwordEncoder() {
            // 使用bcrypt加密
            return new 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

    登录入口

    package com.daben.springsecurityjwt.controller;
    
    import com.daben.springsecurityjwt.entity.SysUser;
    import com.daben.springsecurityjwt.utils.JwtUtil;
    import com.daben.springsecurityjwt.vo.Result;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.core.Authentication;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    /**
     * 登录控制器
     *
     * @Author JinDongSheng
     * @Date 2023-11-15 17:25
     */
    @RestController
    @RequestMapping("/sys/port")
    public class SysPortController {
        @Autowired
        private AuthenticationManager authenticationManager;
        @PostMapping("/login")
        public Result login(@RequestBody SysUser sysUser) {
            // 认证
            Authentication authenticate = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(sysUser.getUsername(), sysUser.getPassword()));
            if (authenticate.isAuthenticated()) {
                // 生成token
                String token = JwtUtil.createToken(sysUser);
                // 返回token
                return Result.success(token);
            }
            return Result.error("用户名或密码错误");
        }
    }
    
    • 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

    整体调用流程

    1. 服务启动,根据【自定义SpringSecurity配置类】配置信息(指定放行和认证接口、token认证过滤器、认证失败处理器、密码加密器、用户查询服务等。)
    2. 用户发起登录请求。
    3. token认证过滤器过滤,因为不携带token,直接放行调用登录接口,在登录接口中手动调用AuthenticationManager进行用户信息认证。
    4. AuthenticationManager进行用户信息认证时会调用【自定义Security用户服务实现类】查询数据库用户,然后将数据库用户封装成Security指定用户返回。
    5. 认证失败调用【自定义认证失败处理类】,认证成功则返回token
    6. 用户发起非登录请求,token过滤器过滤,token校验成功将认证对象放入上下文中。调用请求接口。token校验失败,调用【自定义认证失败处理类】。

    pom文件

    
    <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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0modelVersion>
        <parent>
            <groupId>com.vitalframeworkgroupId>
            <artifactId>vital-framework-dependenciesartifactId>
            <version>1.1.0version>
        parent>
        <groupId>com.citicgroupId>
        <artifactId>vital-portal-coreartifactId>
        <version>1.0.0version>
        <name>vital-portal-corename>
        <description>系统管理(门面工程)模块description>
    
        <properties>
            <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
            <project.rep4orting.outputEncoding>UTF-8project.rep4orting.outputEncoding>
            <java.version>1.8java.version>
            <maven.compiler.source>${java.version}maven.compiler.source>
            <maven.compiler.target>${java.version}maven.compiler.target>
        properties>
    
        <dependencies>
            
            <dependency>
                <groupId>com.vitalframework.webgroupId>
                <artifactId>vital-framework-web-commonartifactId>
                <version>1.0.0version>
            dependency>
    
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
            dependency>
    
            <dependency>
                <groupId>com.alibabagroupId>
                <artifactId>easyexcelartifactId>
            dependency>
            <dependency>
                <groupId>commons-netgroupId>
                <artifactId>commons-netartifactId>
            dependency>
            <dependency>
                <groupId>com.jcraftgroupId>
                <artifactId>jschartifactId>
            dependency>
            
            <dependency>
                <groupId>com.baomidougroupId>
                <artifactId>mybatis-plus-generatorartifactId>
            dependency>
    
            <dependency>
                <groupId>org.apache.poigroupId>
                <artifactId>poiartifactId>
            dependency>
    
            <dependency>
                <groupId>org.apache.poigroupId>
                <artifactId>poi-ooxml-schemasartifactId>
            dependency>
    
            <dependency>
                <groupId>org.apache.poigroupId>
                <artifactId>poi-scratchpadartifactId>
            dependency>
    
            <dependency>
                <groupId>org.codehaus.castorgroupId>
                <artifactId>castor-xmlartifactId>
            dependency>
        dependencies>
    
        <build>
    
            <plugins>
                <plugin>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-maven-pluginartifactId>
                    <configuration>
                        <fork>truefork>
                        <skip>trueskip>
                    configuration>
                plugin>
                <plugin>
                    <groupId>org.apache.maven.pluginsgroupId>
                    <artifactId>maven-source-pluginartifactId>
                    <version>${maven-source-plugin.version}version>
                plugin>
            plugins>
        build>
    project>
    
    • 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
  • 相关阅读:
    mfc140u.dll丢失怎么修复?4种亲测有效的方法分享
    docker镜像编译与docker-compose部署与编排
    可变形卷积
    红细胞膜包裹铜纳米颗粒/红细胞膜修饰普鲁兰纳米粒子/载磁性碳/黑磷量子点细胞膜制备
    playwright录制脚本
    Chatgpt批量改写文章网页版可多开软件-自动登录换号生成word或者TXT
    第一节:Git 安装配置及常用命令
    【附源码】Python计算机毕业设计商场VIP管理系统
    ITSM和ITIL
    NOIP2011-2018提高组解题报告
  • 原文地址:https://blog.csdn.net/BigBang_JJDS/article/details/134456405