SpringSecurity框架快速搭建(SpringBoot整合Security)

这篇具有很好参考价值的文章主要介绍了SpringSecurity框架快速搭建(SpringBoot整合Security)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

Common类

Config类

CorsConfig(解决跨域问题)

RedisConfig (Redis数据库配置)

Spring Security (配置安全功能的类)

expression类(Expression 类通常用于权限控制和安全策略的定义)

SGExpressionRoot(判断用户是否具有某个权限)

Filter类

JwtAuthenticationTokenFilter(解析token看是否放行)

Handler类(通常用于处理特定的请求,事件或异常)

AccessDeniedHandlerImpl类

AuthenticationEntryPoinImpl

Mapper类(根据id查询权限)

Service类

Impl类

UserDetailsServiceImpl

 LoginServiceImpl

Utils类

FastJsonRedisSerializer implements RedisSerializer

 JwtUtil

 RedisCache

 WebUtils

数据库

权限模型

Common类

package com.ma.common;

import com.alibaba.fastjson.annotation.JSONField;
import com.ma.entity.User;
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.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Mtz
 * @version 1.0
 * @2023/5/2317:35
 * @function
 * @comment
 */
@Data
@NoArgsConstructor
public class LoginUser implements UserDetails {
    private User user;

    private List<String> permissions;

    public LoginUser(User user, List<String> permissions) {
        this.user = user;
        this.permissions = permissions;
    }
@JSONField(serialize = false)
    private List<SimpleGrantedAuthority> authorities;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {

        if (authorities != null) {
            return authorities;
        }

        // 把permissions 中String类型的权限信息封装到SimpleGrantedAuthority对象

        authorities = permissions.stream()
                .map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());
        return authorities;
    }

    @Override
    public String getPassword() {
        return user.getPassword();
    }

    @Override
    public String getUsername() {
        return user.getUsername();
    }

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

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

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

    @Override
    public boolean isEnabled() {
        return true;
    }
}
package com.ma.common;

import lombok.Data;
import java.util.HashMap;
import java.util.Map;

@Data
public class R<T> {

    private Integer code; //编码:1成功,0和其它数字为失败

    private String msg; //错误信息

    private T data; //数据

    private Map map = new HashMap(); //动态数据

    public static <T> R<T> success(T object) {
        R<T> r = new R<T>();
        r.data = object;
        r.code = 1;
        return r;
    }

    public static <T> R<T> error(String msg) {
        R r = new R();
        r.msg = msg;
        r.code = 0;
        return r;
    }

    public R<T> add(String key, Object value) {
        this.map.put(key, value);
        return this;
    }

}
package com.ma.common;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Mtz
 * @version 1.0
 * @2023/4/820:25
 * @function
 * @comment
 */
public class CheckData {
public static boolean isUsername(String input) {
    input = input.trim(); // 去除空格
    String regex = "^[a-zA-Z0-9]{5,12}$";
    Pattern pattern = Pattern.compile(regex);
    Matcher matcher = pattern.matcher(input);
    return matcher.matches();
}
    public static boolean isPassword(String password) {
        password = password.trim(); // 去除空格
        String regex = "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=~!])(?=\\S+$).{7,12}$";
        return password.matches(regex);
    }

    public static boolean isQQEmail(String email) {
        email = email.trim(); // 去除空格
        String regex = "^[1-9]\\d{4,10}@qq\\.com$";
        return email.matches(regex);
    }
}
package com.ma.common;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

import java.util.List;


@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class PageResult<T> {
    //当前页
    private int pageNum;
    //每页的数量
    private int pageSize;
    //当前页的数量
    private int size;

    //由于startRow和endRow不常用,这里说个具体的用法
    //可以在页面中"显示startRow到endRow 共size条数据"

    //当前页面第一个元素在数据库中的行号
    private int startRow;
    //当前页面最后一个元素在数据库中的行号
    private int endRow;

    //总记录数
    private long total;
    //总页数
    private int pages;
    //结果集
    private List<T> list;

    //前一页
    private int prePage;
    //下一页
    private int nextPage;
    //是否为第一页
    private boolean isFirstPage;
    //是否为最后一页
    private boolean isLastPage;
    //是否有前一页
    private boolean hasPreviousPage;
    //是否有下一页
    private boolean hasNextPage;
    //导航页码数
    private int navigatePages;
    //所有导航页号
    private int[] navigatepageNums;
    //导航条上的第一页
    private int navigateFirstPage;
    //导航条上的最后一页
    private int navigateLastPage;
}

Config类

CorsConfig(解决跨域问题)

package com.ma.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
      // 设置允许跨域的路径
        registry.addMapping("/**")
                // 设置允许跨域请求的域名
                .allowedOriginPatterns("*")
                // 是否允许cookie
                .allowCredentials(true)
                // 设置允许的请求方式
                .allowedMethods("GET", "POST", "DELETE", "PUT")
                // 设置允许的header属性
                .allowedHeaders("*")
                // 跨域允许时间
                .maxAge(3600);
    }
}

RedisConfig (Redis数据库配置)

package com.ma.config;

import com.ma.utils.FastJsonRedisSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    @Bean
    @SuppressWarnings(value = { "unchecked", "rawtypes" })
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory)
    {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);

        FastJsonRedisSerializer serializer = new FastJsonRedisSerializer(Object.class);

        // 使用StringRedisSerializer来序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(serializer);

        // Hash的key也采用StringRedisSerializer的序列化方式
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(serializer);

        template.afterPropertiesSet();
        return template;
    }
}

Spring Security (配置安全功能的类)

package com.ma.config;

import com.ma.filter.JwtAuthenticationTokenFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * @Author 三更  B站: https://space.bilibili.com/663528522
 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {


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

    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;


    @Autowired
    private AuthenticationEntryPoint entryPoint;

    @Autowired
    private AccessDeniedHandler accessDeniedHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                //关闭csrf
                .csrf().disable()
                //不通过Session获取SecurityContext
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                // 对于登录接口 允许匿名访问
                .antMatchers("/user/login","/static/page/**","/static/css/**", "/static/js/**", "/static/img/**").anonymous()
                // 除上面外的所有请求全部需要鉴权认证
                .anyRequest().authenticated();

        //把token校验过滤器添加到过滤器链中
        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);

        // 配置异常处理器
        http.exceptionHandling()
                //配置认证失败处理器
                .authenticationEntryPoint(entryPoint)
                .accessDeniedHandler(accessDeniedHandler);

        // 允许跨域
        http.cors();
    }

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

expression类(Expression 类通常用于权限控制和安全策略的定义)

SGExpressionRoot(判断用户是否具有某个权限)

package com.ma.expression;

import com.ma.common.LoginUser;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

import java.util.List;

@Component("ex")
public class SGExpressionRoot {

    public boolean hasAuthority(String authority){
        //获取当前用户的权限
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        List<String> permissions = loginUser.getPermissions();
        //判断用户权限集合中是否存在authority
        return permissions.contains(authority);
    }
}

Filter类

JwtAuthenticationTokenFilter(解析token看是否放行)

package com.ma.filter;

import com.ma.common.LoginUser;
import com.ma.utils.JwtUtil;
import com.ma.utils.RedisCache;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
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.Enumeration;
import java.util.Objects;
@Slf4j
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Autowired
    private RedisCache redisCache;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 前端token
        String token = request.getHeader("Authorization");
        if (StringUtils.hasText(token) && token.startsWith("Bearer ")) {
            token = token.substring(7); // 去除 "Bearer " 前缀
        }


        if (!StringUtils.hasText(token)) {
            //放行
            filterChain.doFilter(request, response);
            return;
        }
        //解析token
        String userid;
        try {
            Claims claims = JwtUtil.parseJWT(token);
            userid = claims.getSubject();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("token非法");
        }
        //从redis中获取用户信息
        String redisKey = "login:" + userid;
        LoginUser loginUser = redisCache.getCacheObject(redisKey);
        if (Objects.isNull(loginUser)) {
            throw new RuntimeException("用户未登录");
        }
        //存入SecurityContextHolder
        //TODO 获取权限信息封装到Authentication中

        if (Objects.nonNull(loginUser)) {
            UsernamePasswordAuthenticationToken authenticationToken =
                    new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        }
        //放行
        filterChain.doFilter(request, response);
    }
}

Handler类(通常用于处理特定的请求,事件或异常)

AccessDeniedHandlerImpl类

package com.ma.handler;

import com.alibaba.fastjson.JSON;
import com.ma.common.R;
import com.ma.utils.WebUtils;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        R<String> error = R.error("权限不足");
        String json = JSON.toJSONString(error);
        WebUtils.renderString(response,json);

    }
}

AuthenticationEntryPoinImpl

package com.ma.handler;

import com.alibaba.fastjson.JSON;
import com.ma.common.R;
import com.ma.utils.WebUtils;
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;

@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        R<String> error = R.error("认证失败请重新登录");
        String json = JSON.toJSONString(error);
        WebUtils.renderString(response,json);
    }
}

Mapper类(根据id查询权限)

package com.ma.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

/**
 * @author Mtz
 * @version 1.0
 * @2023/6/116:51
 * @function
 * @comment
 */
@Mapper
public interface BookPermission extends BaseMapper<BookPermission> {
    List<String> selectPermsByUserId(int userid);
}
package com.ma.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ma.entity.User;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

/**
 * @author Mtz
 * @version 1.0
 * @2023/5/2316:53
 * @function
 * @comment
 */
@Mapper
public interface UserMapper extends BaseMapper<User> {
    // 根据用户ID查询对应的角色的role_key
    List<String> findRoleKeyByUserId(Long userId);

    //
    int changPassword(String username, String password);

    int updateUserLogoutOpen(String username);
    int updateUserLogoutOff(String username);
    int updateUserBorrowOpen(String username);
    int updateUserBorrowOff(String username);
}

sql

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- studentMapper.xml -->
<!--  接口路径  -->
<mapper namespace="com.ma.mapper.BookPermission">
    <!-- 获取所有学生信息 -->
    <!--  实体类路径  -->
    <select id="selectPermsByUserId" resultType="java.lang.String">
        SELECT p.prem_key
        FROM book_user u
                 JOIN user_role ur ON u.user_id = ur.user_id
                 JOIN role_permission rp ON ur.role_id = rp.role_id
                 JOIN book_permission p ON rp.permission_id = p.permission_id
        WHERE u.user_id = #{userid} and u.status = '1';
    </select>
</mapper>
    <select id="findRoleKeyByUserId" resultType="java.lang.String">
        SELECT br.role_name
        FROM book_user bu
                 INNER JOIN user_role ur ON bu.user_id = ur.user_id
                 INNER JOIN book_role br ON ur.role_id = br.role_id
        WHERE bu.user_id = #{userId};
    </select>

Service类

package com.ma.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.ma.common.R;
import com.ma.entity.User;

import java.util.HashMap;

/**
 * @author Mtz
 * @version 1.0
 * @2023/5/2410:16
 * @function
 * @comment
 */
public interface LoginService {
    R<HashMap<String, String>> login(User user);

    R<String> logout();
}

Impl类

UserDetailsServiceImpl

package com.ma.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ma.common.LoginUser;
import com.ma.entity.User;
import com.ma.mapper.BookPermission;
import com.ma.mapper.UserMapper;
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.List;
import java.util.Objects;

/**
 * @author Mtz
 * @version 1.0
 * @2023/5/2317:10
 * @function
 * @comment
 */
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private BookPermission bookPermission;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        // 查询用户信息
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, username);
        User user = userMapper.selectOne(queryWrapper);
        // 如果没有查到就抛出异常
        if (Objects.isNull(user)) {
            throw new RuntimeException("用户名或密码错误");
        }


        List<String> list = bookPermission.selectPermsByUserId(user.getUserId());


        return new LoginUser(user, list);
    }
}

 LoginServiceImpl

package com.ma.service.impl;

import com.ma.common.LoginUser;
import com.ma.common.R;
import com.ma.entity.User;
import com.ma.service.LoginService;
import com.ma.service.UserService;
import com.ma.utils.JwtUtil;
import com.ma.utils.RedisCache;
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.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Objects;

/**
 * @author Mtz
 * @version 1.0
 * @2023/5/2410:15
 * @function
 * @comment
 */
@Service
public class LoginServiceImpl implements LoginService {
    @Autowired
    private UserService userService;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private RedisCache redisCache;

    @Override
    public R<HashMap<String, String>> login(User user) {
        // AuthenticationManager authenticate 进行用户认证
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);


        System.out.println("认证..............................................." + authenticate);

        // 如果认证没通过,给出对应的提示
        if (Objects.isNull(authenticate)) {
            throw new RuntimeException("登录失败!");
        }
        // 如果认证通过了,使用userid生成一个jwt, jwt存入R<User> 返回
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        int userId = loginUser.getUser().getUserId();

        String userid = String.valueOf(userId);
        String jwt = JwtUtil.createJWT(userid);


//        // 根据id查询角色是谁
        List<String> roleKeyByUserId = userService.findRoleKeyByUserId((long) userId);

        HashMap<String, String> map = new HashMap<>();
        map.put("token", jwt);
        map.put("userid", String.valueOf(roleKeyByUserId));
        map.put("logoutStatus", String.valueOf(loginUser.getUser().getLogoutStatus()));
        map.put("borrowStatus", String.valueOf(loginUser.getUser().getBorrowingStatus()));
        // 把完整的用户信息存入redis , userid作为key
        redisCache.setCacheObject("login:" + userid, loginUser);
        return R.success(map);
    }

    @Override
    public R<String> logout() {
        //  获取SecurityContextHolder中的用户id
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        Long userid = Long.valueOf(loginUser.getUser().getUserId());
        redisCache.deleteObject("login:" + userid);
        return R.success("退出成功");
    }
}

Utils类

FastJsonRedisSerializer<T> implements RedisSerializer<T>

package com.ma.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import com.alibaba.fastjson.parser.ParserConfig;
import org.springframework.util.Assert;
import java.nio.charset.Charset;

/**
 * Redis使用FastJson序列化
 * 
 * @author sg
 */
public class FastJsonRedisSerializer<T> implements RedisSerializer<T>
{

    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

    private Class<T> clazz;

    static
    {
        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
    }

    public FastJsonRedisSerializer(Class<T> clazz)
    {
        super();
        this.clazz = clazz;
    }

    @Override
    public byte[] serialize(T t) throws SerializationException
    {
        if (t == null)
        {
            return new byte[0];
        }
        return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
    }

    @Override
    public T deserialize(byte[] bytes) throws SerializationException
    {
        if (bytes == null || bytes.length <= 0)
        {
            return null;
        }
        String str = new String(bytes, DEFAULT_CHARSET);

        return JSON.parseObject(str, clazz);
    }


    protected JavaType getJavaType(Class<?> clazz)
    {
        return TypeFactory.defaultInstance().constructType(clazz);
    }
}

 JwtUtil

package com.ma.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;

/**
 * JWT工具类
 */
public class JwtUtil {

    //有效期为
    public static final Long JWT_TTL = 60 * 60 * 1000L;// 60 * 60 *1000  一个小时
    //设置秘钥明文
    public static final String JWT_KEY = "sangeng";

    public static String getUUID() {
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        return token;
    }

    /**
     * 生成jtw
     *
     * @param subject token中要存放的数据(json格式)
     * @return
     */
    public static String createJWT(String subject) {
        JwtBuilder builder = getJwtBuilder(subject, null, getUUID());// 设置过期时间
        return builder.compact();
    }

    /**
     * 生成jtw
     *
     * @param subject   token中要存放的数据(json格式)
     * @param ttlMillis token超时时间
     * @return
     */
    public static String createJWT(String subject, Long ttlMillis) {
        JwtBuilder builder = getJwtBuilder(subject, ttlMillis, getUUID());// 设置过期时间
        return builder.compact();
    }

    private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        SecretKey secretKey = generalKey();
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        if (ttlMillis == null) {
            ttlMillis = JwtUtil.JWT_TTL;
        }
        long expMillis = nowMillis + ttlMillis;
        Date expDate = new Date(expMillis);
        return Jwts.builder()
                .setId(uuid)              //唯一的ID
                .setSubject(subject)   // 主题  可以是JSON数据
                .setIssuer("sg")     // 签发者
                .setIssuedAt(now)      // 签发时间
                .signWith(signatureAlgorithm, secretKey) //使用HS256对称加密算法签名, 第二个参数为秘钥
                .setExpiration(expDate);
    }

    /**
     * 创建token
     *
     * @param id
     * @param subject
     * @param ttlMillis
     * @return
     */
    public static String createJWT(String id, String subject, Long ttlMillis) {
        JwtBuilder builder = getJwtBuilder(subject, ttlMillis, id);// 设置过期时间
        return builder.compact();
    }


        public static void main(String[] args) throws Exception {
//        String jwt = createJWT("1234");
//        System.out.println(jwt); // 生成的token
        Claims claims = parseJWT("eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJiMTY0MTk3M2U3OGI0ODdhYjcxZjUyYWQxNTc5ZTY0NSIsInN1YiI6IjIiLCJpc3MiOiJzZyIsImlhdCI6MTY4NDg5ODU4OSwiZXhwIjoxNjg0OTAyMTg5fQ.LSPpV7aOwgsWjxJidPkugb7BkiIaQj4adc5o1hcenSc"); // 解密
        String subject = claims.getSubject();
        System.out.println(subject);
    }



    /**
     * 生成加密后的秘钥 secretKey
     *
     * @return
     */
    public static SecretKey generalKey() {
        byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }

    /**
     * 解析
     *
     * @param jwt
     * @return
     * @throws Exception
     */
    public static Claims parseJWT(String jwt) throws Exception {
        SecretKey secretKey = generalKey();
        return Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(jwt)
                .getBody();
    }


}

 RedisCache

package com.ma.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;

@SuppressWarnings(value = { "unchecked", "rawtypes" })
@Component
public class RedisCache
{
    @Autowired
    public RedisTemplate redisTemplate;

    /**
     * 缓存基本的对象,Integer、String、实体类等
     *
     * @param key 缓存的键值
     * @param value 缓存的值
     */
    public <T> void setCacheObject(final String key, final T value)
    {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 缓存基本的对象,Integer、String、实体类等
     *
     * @param key 缓存的键值
     * @param value 缓存的值
     * @param timeout 时间
     * @param timeUnit 时间颗粒度
     */
    public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit)
    {
        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
    }

    /**
     * 设置有效时间
     *
     * @param key Redis键
     * @param timeout 超时时间
     * @return true=设置成功;false=设置失败
     */
    public boolean expire(final String key, final long timeout)
    {
        return expire(key, timeout, TimeUnit.SECONDS);
    }

    /**
     * 设置有效时间
     *
     * @param key Redis键
     * @param timeout 超时时间
     * @param unit 时间单位
     * @return true=设置成功;false=设置失败
     */
    public boolean expire(final String key, final long timeout, final TimeUnit unit)
    {
        return redisTemplate.expire(key, timeout, unit);
    }

    /**
     * 获得缓存的基本对象。
     *
     * @param key 缓存键值
     * @return 缓存键值对应的数据
     */
    public <T> T getCacheObject(final String key)
    {
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        return operation.get(key);
    }

    /**
     * 删除单个对象
     *
     * @param key
     */
    public boolean deleteObject(final String key)
    {
        return redisTemplate.delete(key);
    }

    /**
     * 删除集合对象
     *
     * @param collection 多个对象
     * @return
     */
    public long deleteObject(final Collection collection)
    {
        return redisTemplate.delete(collection);
    }

    /**
     * 缓存List数据
     *
     * @param key 缓存的键值
     * @param dataList 待缓存的List数据
     * @return 缓存的对象
     */
    public <T> long setCacheList(final String key, final List<T> dataList)
    {
        Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
        return count == null ? 0 : count;
    }

    /**
     * 获得缓存的list对象
     *
     * @param key 缓存的键值
     * @return 缓存键值对应的数据
     */
    public <T> List<T> getCacheList(final String key)
    {
        return redisTemplate.opsForList().range(key, 0, -1);
    }

    /**
     * 缓存Set
     *
     * @param key 缓存键值
     * @param dataSet 缓存的数据
     * @return 缓存数据的对象
     */
    public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet)
    {
        BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
        Iterator<T> it = dataSet.iterator();
        while (it.hasNext())
        {
            setOperation.add(it.next());
        }
        return setOperation;
    }

    /**
     * 获得缓存的set
     *
     * @param key
     * @return
     */
    public <T> Set<T> getCacheSet(final String key)
    {
        return redisTemplate.opsForSet().members(key);
    }

    /**
     * 缓存Map
     *
     * @param key
     * @param dataMap
     */
    public <T> void setCacheMap(final String key, final Map<String, T> dataMap)
    {
        if (dataMap != null) {
            redisTemplate.opsForHash().putAll(key, dataMap);
        }
    }

    /**
     * 获得缓存的Map
     *
     * @param key
     * @return
     */
    public <T> Map<String, T> getCacheMap(final String key)
    {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * 往Hash中存入数据
     *
     * @param key Redis键
     * @param hKey Hash键
     * @param value 值
     */
    public <T> void setCacheMapValue(final String key, final String hKey, final T value)
    {
        redisTemplate.opsForHash().put(key, hKey, value);
    }

    /**
     * 获取Hash中的数据
     *
     * @param key Redis键
     * @param hKey Hash键
     * @return Hash中的对象
     */
    public <T> T getCacheMapValue(final String key, final String hKey)
    {
        HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
        return opsForHash.get(key, hKey);
    }

    /**
     * 删除Hash中的数据
     * 
     * @param key
     * @param hkey
     */
    public void delCacheMapValue(final String key, final String hkey)
    {
        HashOperations hashOperations = redisTemplate.opsForHash();
        hashOperations.delete(key, hkey);
    }

    /**
     * 获取多个Hash中的数据
     *
     * @param key Redis键
     * @param hKeys Hash键集合
     * @return Hash对象集合
     */
    public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys)
    {
        return redisTemplate.opsForHash().multiGet(key, hKeys);
    }

    /**
     * 获得缓存的基本对象列表
     *
     * @param pattern 字符串前缀
     * @return 对象列表
     */
    public Collection<String> keys(final String pattern)
    {
        return redisTemplate.keys(pattern);
    }
}

 WebUtils

package com.ma.utils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class WebUtils
{
    /**
     * 将字符串渲染到客户端
     * 
     * @param response 渲染对象
     * @param string 待渲染的字符串
     * @return null
     */
    public static String renderString(HttpServletResponse response, String string) {
        try
        {
            response.setStatus(200);
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            response.getWriter().print(string);
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        return null;
    }
}

数据库

权限模型

SpringSecurity框架快速搭建(SpringBoot整合Security)文章来源地址https://www.toymoban.com/news/detail-492555.html

use test;
CREATE TABLE `sys_user` (
  `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `username` VARCHAR(64) NOT NULL DEFAULT 'NULL' COMMENT '用户名',
  `password` VARCHAR(64) NOT NULL DEFAULT 'NULL' COMMENT '密码',
  `status` CHAR(1) DEFAULT '0' COMMENT '账号状态(0正常 1停用)',
  PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

CREATE TABLE `sys_menu` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `menu_name` varchar(64) NOT NULL DEFAULT 'NULL' COMMENT '菜单名',
  `path` varchar(200) DEFAULT NULL COMMENT '路由地址',
  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='菜单表';

CREATE TABLE `sys_role` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(128) DEFAULT NULL,
  `status` char(1) DEFAULT '0' COMMENT '角色状态(0正常 1停用)',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COMMENT='角色表';

CREATE TABLE `sys_role_menu` (
  `role_id` bigint(200) NOT NULL AUTO_INCREMENT COMMENT '角色ID',
  `menu_id` bigint(200) NOT NULL DEFAULT '0' COMMENT '菜单id',
  PRIMARY KEY (`role_id`,`menu_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;

CREATE TABLE `sys_user_role` (
  `user_id` bigint(200) NOT NULL AUTO_INCREMENT COMMENT '用户id',
  `role_id` bigint(200) NOT NULL DEFAULT '0' COMMENT '角色id',
  PRIMARY KEY (`user_id`,`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

SELECT DISTINCT path
FROM sys_user u
JOIN sys_user_role ur ON u.id = ur.user_id
JOIN sys_role_menu rm ON ur.role_id = rm.role_id
JOIN sys_menu m ON rm.menu_id = m.id
WHERE u.id = 1
  AND u.status = 0;

到了这里,关于SpringSecurity框架快速搭建(SpringBoot整合Security)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • SpringBoot整合SpringSecurity详细教程(实战开发讲解)

    今天小编使用到了SpringBoot+SpringSecurity进行公司项目开发,之前使用到项目都是采用xml配置来整合SpringSecurity,对于第一次使用SpringBoot整合SpringSecurity也是比较陌生,过程中也是遇到各种各样的问题,在CSDN的知识海洋中遗留的相关的整合教程也是五花八门,找一篇完整的教程简

    2024年02月15日
    浏览(28)
  • springboot整合springsecurity+oauth2.0密码授权模式

    本文采用的springboot去整合springsecurity,采用oauth2.0授权认证,使用jwt对token增强。本文仅为学习记录,如有不足多谢提出。 OAuth 2.0是用于授权的行业标准协议。OAuth 2.0为简化客户端开发提供了特定的授权流,包括Web应用、桌面应用、移动端应用等。 Resource owner(资源拥有者)

    2024年02月04日
    浏览(44)
  • SpringBoot3整合SpringSecurity,实现自定义接口权限过滤

    接口权限过滤是指对于某些接口或功能,系统通过设定一定的权限规则,只允许经过身份认证且拥有相应权限的用户或应用程序进行访问和操作 。这种技术可以有效地保护系统资源和数据安全,防止未授权的用户或程序进行恶意操作或非法访问。通常情况下,接口权限过滤需

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

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

    2024年02月07日
    浏览(33)
  • Spring Security入门教程,springboot整合Spring Security

    Spring Security是Spring官方推荐的认证、授权框架,功能相比Apache Shiro功能更丰富也更强大,但是使用起来更麻烦。 如果使用过Apache Shiro,学习Spring Security会比较简单一点,两种框架有很多相似的地方。 目录 一、准备工作 创建springboot项目 pom.xml application.yml 二、创建相关的类

    2024年02月05日
    浏览(35)
  • 若依框架(一)使用若依框架从0到1快速搭建springboot + vue 项目

    1、下载若依框架代码 进入若依官网,选择源码地址,软后选择RuoYi-Vue前端分离版本,这个版本是由SpringBoot + Vue进行前后端分离开发的。 点击之后进入到gitee,点击 “克隆/下载”,选择下载方式,可以实用git命令进行git克隆,也可以直接选择下载zip,这里推荐新手就下载z

    2024年02月16日
    浏览(28)
  • 【万字长文】SpringBoot整合SpringSecurity+JWT+Redis完整教程(提供Gitee源码)

    前言:最近在学习SpringSecurity的过程中,参考了很多网上的教程,同时也参考了一些目前主流的开源框架,于是结合自己的思路写了一个SpringBoot整合SpringSecurity+JWT+Redis完整的项目,从0到1写完感觉还是收获到不少的,于是我把我完整的笔记写成博客分享给大家,算是比较全的

    2024年02月15日
    浏览(28)
  • SpringBoot整合Spring Security实现权限控制

    要对Web资源进行保护,最好的办法莫过于Filter 要想对方法调用进行保护,最好的办法莫过于AOP。 Spring Security进行认证和鉴权的时候,就是利用的一系列的Filter来进行拦截的。 如图所示,一个请求想要访问到API就会从左到右经过蓝线框里的过滤器,其中 绿色部分是负责认证的

    2024年02月15日
    浏览(29)
  • SpringSecurity源码分析(一) SpringBoot集成SpringSecurity即Spring安全框架的加载过程

          Spring Security是一个强大的并且高度可定制化的访问控制框架。 它基于spring应用。 Spring Security是聚焦于为java应用提供授权和验证的框架。像所有的spring项目一样,Spring Security真正的强大在于可以非常简单的拓展功能来实现自定义的需求。       在分析SpringBoot集成的Sp

    2024年02月03日
    浏览(32)
  • 【已解决】SpringBoot整合security账号密码正确却提示错误

    SpringSecurity的密码校验并不是直接使用原文进行比较,而是使用加密算法将密码进行加密(更准确地说应该进行Hash处理,此过程是不可逆的,无法解密),最后将用户提供的密码以同样的方式加密后与密文进行比较。对于我们来说,用户提供的密码属于隐私信息,直接明文存

    2024年02月11日
    浏览(33)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包