首页 > 其他分享 >springboot3项目的搭建四.1(security登录认证配置)

springboot3项目的搭建四.1(security登录认证配置)

时间:2024-05-31 21:45:49浏览次数:21  
标签:return String springframework 认证 springboot3 org import security

SpringBoot3 整合SpringSecurity

Maven

  <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
     <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

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

JwtFilter

package com.system.security;

import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.system.common.exception.ServerException;
import com.system.common.utlis.jwt.JwtUtils;
import com.system.common.utlis.result.Prefix;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

/**
 * @author kuaiting
 */
@Component
public class JwtFilter extends OncePerRequestFilter {
    @Resource
    private JwtUtils jwtUtils;

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        // 实现过滤逻辑
        String authorization = request.getHeader(Prefix.TOKEN_KEY);
        System.out.println(authorization);
        if (authorization != null && authorization.startsWith(Prefix.TOKEN_BEARER)) {
            // 验证JWT并设置用户信息到SecurityContextHolder中
            DecodedJWT jwt = jwtUtils.resolveToken(authorization);
            if (jwt != null) {
                Long uid = jwtUtils.getUid(jwt);
                SecurityUser details = jwtUtils.getUserDetails(jwt);
                UsernamePasswordAuthenticationToken authentication =
                        new UsernamePasswordAuthenticationToken(details, null, details.getAuthorities());
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authentication);
                request.setAttribute("uid", uid);
            }
        }
        filterChain.doFilter(request, response);
    }


    public void validate(HttpServletRequest request) throws ServerException {
        //请求中传来的验证码
        String code = request.getParameter("code");
        String sessionCode = request.getSession().getAttribute("session_code").toString();
        if (StrUtil.isEmpty(code)) {
            throw new ServerException("验证码不能为空!");
        }
        if (StrUtil.isEmpty(sessionCode)) {
            throw new ServerException("验证码已经失效!");
        }
        if (!sessionCode.equalsIgnoreCase(code)) {
            throw new ServerException("验证码输入错误!");
        }

    }

}

SecurityConfig

package com.system.security;

import com.system.common.utlis.jwt.JwtUtils;
import com.system.common.utlis.result.Prefix;
import com.system.common.utlis.result.ResData;
import com.system.common.utlis.result.ResEnum;
import com.system.system.dao.RoleDao;
import com.system.system.entity.vo.AuthVO;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author kuaiting
 */
@Configuration
public class SecurityConfig {

    @Resource
    JwtUtils jwtUtils;

    @Resource
    private JwtFilter jwtFilter;

    @Resource
    private RoleDao roleDao;



    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    private final String[] paths = {
            "/druid/**", "/system/captcha/line",
            "/druid/login.html/**",
            "/system/login", "/js/**", "/*/*.json", "/*/*.yml",
            "/prims/**", "/type/**", "/system/file/**",
            "/diagram-viewer/**", "/images/**",
            "/api/login/**", "/api/file/**",
            "/css/**", "/*/*.ico", "/swagger-resources/**",
            "/swagger/**", "/swagger-ui/**",
            "/webjars/**", "/v3/**", "/v2/**", "/doc.html/**"
    };

    @Bean
    public SecurityFilterChain securityChain(HttpSecurity http) throws Exception {

        return http.authorizeHttpRequests(conf -> conf.requestMatchers(paths).permitAll()
                .anyRequest().authenticated())
                .formLogin(conf ->
                        conf.loginProcessingUrl("/system/login")
                        .usernameParameter("username")
                        .passwordParameter("password")
                        .successHandler(this::onAuthenticationSuccess)
                        .failureHandler(this::onAuthenticationFailure))
                .exceptionHandling(conf ->
                         conf.authenticationEntryPoint(this::noLogin)
                        .accessDeniedHandler(this::noPermission))
                .logout(conf ->
                         conf.logoutUrl("/system/logout")
                        .logoutSuccessHandler(this::onLogoutSuccess))
                .csrf(AbstractHttpConfigurer::disable)
                .sessionManagement(conf -> conf.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
                .build();

    }

    private void noPermission(HttpServletRequest request,
                              HttpServletResponse response,
                              AccessDeniedException e) throws IOException {
        response.setContentType("application/json;charset=UTF-8");
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        PrintWriter writer = response.getWriter();
        jsonWriter(writer, ResEnum.FORBIDDEN.getCode(), ResEnum.FORBIDDEN.getMsg());

    }

    public void onAuthenticationSuccess(HttpServletRequest request,
                                        HttpServletResponse response,
                                        Authentication authentication) throws IOException {
        SecurityUser user = (SecurityUser) authentication.getPrincipal();
        Long uid = user.getId();
        Set<String> permissions = new HashSet<>();
        for (GrantedAuthority authority : user.getAuthorities()) {
            String auth = authority.getAuthority();
            permissions.add(auth);
        }
        String token = jwtUtils.createToken(user, uid, user.getUsername(),user.getPassword());
        AuthVO authVo = new AuthVO();
        authVo.setRole(roleDao.getUserRoles(uid));
        authVo.setPermission(permissions);
        authVo.setKey(Prefix.TOKEN_KEY);
        authVo.setToken(token);
        authVo.setExpire(jwtUtils.expireTime().getTime());
        response.setContentType("application/json;charset=UTF-8");
        response.setStatus(HttpServletResponse.SC_OK);
        PrintWriter writer = response.getWriter();
        jsonWriter(writer, ResEnum.SUCCESS.getCode(), ResEnum.SUCCESS.getMsg(), authVo);
    }

    public void onAuthenticationFailure(HttpServletRequest request,
                                        HttpServletResponse response,
                                        AuthenticationException exception) throws IOException {
        response.setContentType("application/json;charset=UTF-8");
        response.setStatus(HttpServletResponse.SC_OK);
        PrintWriter writer = response.getWriter();
        jsonWriter(writer, ResEnum.UNAUTHORIZED.getCode(), exception.getMessage());
    }

    public void noLogin(HttpServletRequest request, HttpServletResponse response,
                        AuthenticationException authException) throws IOException {
        response.setContentType("application/json;charset=UTF-8");
        response.setStatus(HttpServletResponse.SC_OK);
        PrintWriter writer = response.getWriter();
        jsonWriter(writer, ResEnum.UNAUTHORIZED.getCode(), ResEnum.UNAUTHORIZED.getMsg());
    }


    public void onLogoutSuccess(HttpServletRequest request,
                                HttpServletResponse response,
                                Authentication authentication) throws IOException {
        String authorization = request.getHeader("Authorization");
        response.setContentType("application/json;charset=UTF-8");
        response.setStatus(HttpServletResponse.SC_OK);
        PrintWriter writer = response.getWriter();
        // 登出时,删除redis中的token
        if (jwtUtils.invalidateToken(authorization)) {
            jsonWriter(writer, ResEnum.SUCCESS.getCode(), ResEnum.SUCCESS.getMsg());
        } else {
            jsonWriter(writer, ResEnum.FAIL.getCode(), ResEnum.FAIL.getMsg());
        }


    }

    private void jsonWriter(PrintWriter writer, Integer code, String message) {
        jsonWriter(writer, code, message, null);
    }

    private void jsonWriter(PrintWriter writer, Integer code, String message, Object data) {
        writer.write(ResData.asJson(code, message, data));
        writer.flush();
        writer.close();
    }


    private List<Long> getRoleIds(Long uid) {
        return roleDao.getRoleIds(uid);
    }

    private List<String> getUserRoles(Long uid) {
        return roleDao.getUserRoles(uid);
    }

    private Set<String> getPermissions(List<Long> roleIds) {
        Set<String> all = new HashSet<>();
        for (Long id : roleIds) {
            List<String> permissions = getUserPermissions(id);
            all.addAll(permissions);
        }
        return all;
    }

    private List<String> getUserPermissions(Long rid) {
        return roleDao.getPermissions(rid);
    }


}

User

package com.system.security;

import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.io.Serializable;
import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author kuaiting
 */
@Data
@NoArgsConstructor
public class SecurityUser implements UserDetails, Serializable {
    private Long id;
    private String username;
    private String password;
    private Integer status;
    private Set<String> permissions;
    private  Collection<? extends GrantedAuthority> authorities;


    public SecurityUser( Long id,String username, String password, Integer status, Set<String> permissions) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.status = status;
        this.permissions = permissions;
    }


    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        if (authorities != null) {
            return authorities;
        }
        //把permissions中字符串类型的权限信息转换成GrantedAuthority对象存入authorities中
        authorities = permissions.stream().
                map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());
        return authorities;
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public String getUsername() {
        return username;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return status == 0;
    }
}

JwtUtils

package com.system.common.utlis.jwt;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.system.common.utlis.redis.RedisService;
import com.system.common.utlis.result.Prefix;
import com.system.security.SecurityUser;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

@Component
public class JwtUtils {
    @Value("${jwt.secret}")
    private String secret;
    @Value("${jwt.expire}")
    private Integer expire;

    @Resource
    private RedisService redisService;

    public Boolean invalidateToken(String haeadToken) {
        String token = convertToken(haeadToken);
        if (token == null) {
            return false;
        }
        try {
            DecodedJWT jwt = JWT.require(Algorithm.HMAC256(secret)).build().verify(token);
            return deleteToken(jwt.getId(), jwt.getExpiresAt());
        } catch (JWTVerificationException e) {
            return null;
        }
    }

    // 删除redis 中的Token
    private Boolean deleteToken(String id, Date date) {
        if (isInvalidToken(id)) {
            return false;
        }
        Date now = new Date();
        long expire = Math.max(date.getTime() - now.getTime(), 0);
        redisService.set(Prefix.JWT_BLACK_LIST + id, id, expire);
        return true;
    }

    // 验证 redis 中 token 是否存在
    private Boolean isInvalidToken(String id) {
        return Boolean.TRUE.equals(redisService.hasKey(Prefix.JWT_BLACK_LIST + id));
    }


    public String createToken(UserDetails details, Long id, String username,String password) {
        Algorithm algorithm = Algorithm.HMAC256(secret);
        redisService.set(Prefix.JWT_BLACK_LIST + id, id, expire);
        return JWT.create().withJWTId(String.valueOf(id))
                .withClaim("id", id)
                .withClaim("username", username)
                .withClaim("password", password)
                .withClaim("authorities", getAuths(details))
                .withExpiresAt(expireTime())
                .sign(algorithm);
    }

    public String getAuths(UserDetails details) {
        return details.getAuthorities().stream().map(GrantedAuthority::getAuthority).
                collect(Collectors.joining(","));
    }

    // 获取过期时间
    public Date expireTime() {
        // 过期时间
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.HOUR, expire * 24); // 默认7天
        return instance.getTime();
    }

    // 解析 JWT token
    public DecodedJWT resolveToken(String haeadToken) {
        String token = convertToken(haeadToken);
        if (token == null) {
            return null;
        }
        try {
            DecodedJWT jwt = JWT.require(Algorithm.HMAC256(secret)).build().verify(token);
            if (isInvalidToken(jwt.getId())) {
                return null;
            }
            Date expires = jwt.getExpiresAt();
            return new Date().after(expires) ? null : jwt;
        } catch (JWTVerificationException e) {
            return null;
        }
    }

    // 解析 截取真正有用的token
    private String convertToken(String haeadToken) {
        if (haeadToken == null || !haeadToken.startsWith(Prefix.TOKEN_BEARER)) {
            return null;
        }
        return haeadToken.substring(7);
    }

    // 获取用户信息
    public SecurityUser getUserDetails(DecodedJWT jwt) {
        Map<String, Claim> claims = jwt.getClaims();
        String authorities = claims.get("authorities").asString();
        Set<SimpleGrantedAuthority> permissions = new HashSet<>();
        for (String auth : authorities.split(",")) {
            permissions.add(new SimpleGrantedAuthority(auth));
        }
        SecurityUser sysUser = new SecurityUser();
        sysUser.setId(jwt.getClaim("id").asLong());
        sysUser.setUsername(claims.get("username").toString());
        sysUser.setPassword(claims.get("password").toString());
        sysUser.setStatus(0);
        sysUser.setAuthorities(permissions);
        return sysUser;
    }

    // 获取用户ID
    public Long getUid(DecodedJWT jwt) {
        return jwt.getClaim("id").asLong();
    }
}

 

 

 

 

转:https://blog.csdn.net/qq_45834006/article/details/136403939

 https://docs.spring.io/spring-security/reference/index.html

 

标签:return,String,springframework,认证,springboot3,org,import,security
From: https://www.cnblogs.com/fps2tao/p/18225313

相关文章

  • springboot3项目的搭建四.2(security登录认证配置)
    SpringBoot3+SpringSecurity整合Security导包:<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency>模拟Redis存储登录信息:publicclassCacheEntityimpl......
  • springboot3项目的搭建四(security登录认证配置)
    springboot3项目的搭建四(security登录认证配置)  <!--security安全配置--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifact......
  • SpringSecurity权限验证
    目录我们先用默认的一个访问拦截页面第二种,我们可以自己写一个登录的页面,也就是没有权限被拦截之后的登录页面我们先用默认的一个访问拦截页面首先先加入我们的Security的一个依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>s......
  • WEB安全:Content Security Policy (CSP) 详解
    ContentSecurityPolicy(CSP)是一种强大的网页安全机制,用于防止跨站脚本(XSS)和其他注入攻击。通过设置一系列的内容安全策略,CSP可以限制网页可以加载的资源,从而保护用户数据和网站的安全性。什么是XSS攻击?跨站脚本攻击(XSS)是一种常见的安全漏洞,攻击者通过注......
  • nginx配置下载站,增加用户认证,增加统计功能
    1.配置文件如下server{listen80;server_namevideo.tom.com;error_log/var/log/nginx/video.tom.cn/err.lognotice;access_log/var/log/nginx/video.tom.cn/access.logmain;root/app/code/video;charsetutf8;#支持中文autoindex......
  • 【网络通信】初探Google的reCAPTCHA安全认证技术
        在数字化日益普及的今天,如何有效保护网站免受恶意攻击和滥用成为了每个网站管理员和开发者必须面对的重要问题。而reCAPTCHA正是Google提供的一种强大且智能的解决方案,旨在通过人机验证来增强网站的安全性。一、reCAPTCHA简介        reCAPTCHA是Google推......
  • springboot3项目的搭建三(统一返回异常等)
    springboot3项目的搭建三(统一返回异常等) 一、统一返回(其实两部分,一个是返回错误码可枚举可类,另一个是返回的实体其中data是泛型)1.返回码:packagecom.qiqi.common.constants;publicenumReturnCode{SUCCESS(200,"操作成功"),NEED_LOGIN(401,"需要登录后操作......
  • 6.基于传统的Cookie和Session实现用户的认证授权
    6.1概述RBAC(Role-BasedAccessControl,基于角色的访问控制)权限按钮控制是一种细粒度的权限管理方式,它允许系统管理员根据用户的角色来精确控制用户界面中功能按钮的可见性和可用性。在RBAC模型中,权限不仅限于访问某个页面或模块,还可以细化到页面上每个操作按钮的权限。......
  • AJ-Report 认证绕过与远程代码执行漏洞(CNVD-2024-15077)
    AJ-Report是全开源的一个BI平台。在其1.4.0版本及以前,存在一处认证绕过漏洞,攻击者利用该漏洞可以绕过权限校验并执行任意代码。补丁对比方法一从docker拖出代码,去gitee下载发行版,便于对比编译后的class。方法二查看git的commit记录,可以直接看到修改了哪些内容!后面要去学习......
  • 【Spring Security】Error:A granted authority textual representation is required
     Security出错了! 分析:Debug跑后 排查是Security中的UserDetails.getAuthorities()在创建SimpleGrantedAuthorityauthority时,所传递的授权信息是空的,导致SimpleGrantedAuthorityauthority出现异常;报出Agrantedauthoritytextualrepresentationisreq......