Spring Security前后分离校验token的实现方法

 更新时间:2022年02月25日 09:17:17   作者:专注写bug  
这篇文章主要介绍了Spring Security前后分离校验token的方法,本次token生成采取jwt的方式,通过引入jwt依赖文件配置token管理器,对Spring Security校验token相关知识感兴趣的朋友一起看看吧

前言

之前采取项目中嵌套html页面,实现基本的登录校验权限校验登出操作记住我等功能试下。

但是,现在的开发基本都是前后分离样式,后端并不需要配置登录页的操作。

如何才能做到前后分离,同时也能支持登录token校验呢,本篇博客详细说明。

token配置

本次token生成采取jwt的方式。

引入JWT依赖文件

<dependency>
  <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.10.3</version>
</dependency>

配置token管理器类

自定一个Token生成和从token中解析用户名的一个类,并交给Spring管理。

package security.config;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.springframework.stereotype.Component;
import java.util.Calendar;
import java.util.HashMap;
@Component
public class TokenJwtManager {
    // 设置token时间
    private int tokenEcpiration = 24*60*60*1000; // 毫秒   24h
    // 编码密钥
    private String tokenSignKey = "123456";
    // 1、根据用户名生成token
    public String createToken(String userName){
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND, tokenEcpiration);
        String userName1 = JWT.create()
                .withHeader(new HashMap<>())
                .withClaim("userName", userName)
                .withExpiresAt(calendar.getTime()) // 过期时间
                .sign(Algorithm.HMAC256(tokenSignKey));// 签名
        return userName1;
    }
    // 2、根据token得到用户名信息
    public String getUserName(String token){
        JWTVerifier build = JWT.require(Algorithm.HMAC256(tokenSignKey)).build();
        DecodedJWT verify = build.verify(token);
        Claim userName = verify.getClaim("userName");
        return userName.asString();
    public static void main(String[] args) {
        String ss = new TokenJwtManager().createToken("1111111");
        System.out.println(ss);
        System.out.println(new TokenJwtManager().getUserName(ss));
}

security 配置

配置未登录处理类

package security.config.handler;

import lombok.extern.slf4j.Slf4j;
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;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
/**
 * 未登录
 */
@Component
@Slf4j
public class MyUnAuthEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        log.info("======= commence ===");
        // 返回请求端
        Map<String,Object> resultMap = new HashMap<>();
        // 保存数据
        resultMap.put("code","10000");
        resultMap.put("msg","当前账户未登录");
        resultMap.put("data",new HashMap<>());
        // 设置返回消息类型
        httpServletResponse.setHeader("Content-type", "text/html;charset=UTF-8");
        httpServletResponse.setCharacterEncoding("utf-8");
        httpServletResponse.setContentType("application/json;charset=UTF-8");
        // 返回给请求端
        PrintWriter writer  = httpServletResponse.getWriter();
        writer.write(resultMap.toString());
        writer.close();
    }
}

配置无权限处理类

package security.config.handler;

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;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
/**
 * 无权访问配置(前后分离)
 */
@Component  // 交给spring管理
public class MyAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
        Map<String,Object> resultMap = new HashMap<>();
        // 保存数据
        resultMap.put("code","403");
        resultMap.put("msg","无权访问");
        resultMap.put("data",null);
        // 设置返回消息类型
        httpServletResponse.setHeader("Content-type", "text/html;charset=UTF-8");
        httpServletResponse.setCharacterEncoding("utf-8");
        httpServletResponse.setContentType("application/json;charset=UTF-8");
        // 返回给请求端
        PrintWriter writer = httpServletResponse.getWriter();
        writer.write(resultMap.toString());
        writer.flush();
        writer.close();
    }
}

配置登出操作处理类

package security.config.handler;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.stereotype.Component;
import security.config.TokenJwtManager;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
/**
 * 登出
 */
@Component
@Slf4j
public class MyLogoutHandler implements LogoutHandler {
    @Autowired
    private TokenJwtManager tokenJwtManager;
//    public MyLogoutHandler(TokenJwtManager tokenJwtManager) {
//        this.tokenJwtManager = tokenJwtManager;
//    }
    @Override
    public void logout(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) {
        // 1、从header中获取token
        String token = httpServletRequest.getHeader("token");
        log.info("token信息为  {}",token);
        String userName = tokenJwtManager.getUserName(token);
        log.info("从token获取userName信息为  {}",token);
        // redis 移除登录信息等逻辑
        // xxxxx
        // 2、返回请求端
        Map<String,Object> resultMap = new HashMap<>();
        // 保存数据
        resultMap.put("code","200");
        resultMap.put("msg",userName+"登录成功");
        resultMap.put("data",new HashMap<>());
        // 设置返回消息类型
        httpServletResponse.setHeader("Content-type", "text/html;charset=UTF-8");
        httpServletResponse.setCharacterEncoding("utf-8");
        httpServletResponse.setContentType("application/json;charset=UTF-8");
        // 返回给请求端
        PrintWriter writer = null;
        try {
            writer = httpServletResponse.getWriter();
            writer.write(resultMap.toString());
            writer.flush();
            writer.close();
        } catch (IOException e) {
           e.printStackTrace();
        }
    }
}

配置token认证过滤器

package security.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
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.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;
import security.config.TokenJwtManager;
import security.vo.SecurityUser;
import security.vo.User;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
// 这里交给spring管理会报错
@Slf4j
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
    private TokenJwtManager tokenJwtManager;
    private AuthenticationManager authenticationManager;
    public TokenLoginFilter(TokenJwtManager tokenJwtManager, AuthenticationManager authenticationManager) {
        this.tokenJwtManager = tokenJwtManager;
        this.authenticationManager = authenticationManager;
        this.setPostOnly(false); // 关闭登录只允许 post
        // 设置登陆路径,并且post请求
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/user/login","POST"));
    }
    // 1、获取登录页传递来的账户和密码信息
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response){
        log.info("==== attemptAuthentication  ======");
        String userName = request.getParameter("userName");
        String pwd = request.getParameter("passWord");
        log.info("userName:{},pwd:{}",userName,pwd);
        return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(userName,
                pwd,new ArrayList<>()));
    // 2、认证成功调用
    @Autowired
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult)
            throws IOException, ServletException {
        log.info("==== successfulAuthentication  ======");
        // 认证成功之后,获取认证后的用户基本信息
        SecurityUser securityUser = (SecurityUser) authResult.getPrincipal();
        // 根据用户名生成对应的token
        String token = tokenJwtManager.createToken(securityUser.getUsername());
        // token信息存于redis、数据库、缓存等
        // 返回成功
        Map<String,Object> resultMap = new HashMap<>();
        // 保存数据
        resultMap.put("code","200");
        resultMap.put("msg","登录成功");
        resultMap.put("data",token);
        // 设置返回消息类型
        response.setHeader("Content-type", "text/html;charset=UTF-8");
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json;charset=UTF-8");
        // 返回给请求端
        PrintWriter writer = response.getWriter();
        writer.write(resultMap.toString());
        writer.flush();
        writer.close();
    // 3、认证失败调用的方法
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed)
        log.info("==== unsuccessfulAuthentication  ======");
        resultMap.put("code","500");
        resultMap.put("msg","登录验证失败");
        resultMap.put("data",new HashMap<>());
}

配置token权限校验过滤器

package security.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.stereotype.Component;
import security.config.TokenJwtManager;
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.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/**
 * token 校验
 */
@Slf4j
//@Component // 交给 spring 会报错
public class TokenAuthFilter extends BasicAuthenticationFilter {
    private TokenJwtManager tokenJwtManager;
    public TokenAuthFilter(AuthenticationManager authenticationManager, TokenJwtManager tokenJwtManager) {
        super(authenticationManager);
        this.tokenJwtManager = tokenJwtManager;
    }
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        log.info("====  doFilterInternal   ==========   token校验");
        //获取当前认证成功用户权限信息
        UsernamePasswordAuthenticationToken authRequest = getAuthentication(request);
        if(authRequest != null){
            // 有权限,则放入权限上下文中
            SecurityContextHolder.getContext().setAuthentication(authRequest);
        }
        // 执行下一个 filter 过滤器链
        chain.doFilter(request,response);
    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
        log.info("==== getAuthentication =====");
        //从header获取token
        String token = request.getHeader("token");
        log.info("token:{}",token);
        if(token != null) {
            //从token获取用户名
            String username = tokenJwtManager.getUserName(token);
            log.info("解析token获取userName为:{}",username);
            // 数据库获取权限信息
            // 本次模拟
            List<String> permissionValueList = Arrays.asList("admin","select");
            Collection<GrantedAuthority> authority = new ArrayList<>();
            for(String permissionValue : permissionValueList) {
                SimpleGrantedAuthority auth = new SimpleGrantedAuthority(permissionValue);
                authority.add(auth);
            }
            return new UsernamePasswordAuthenticationToken(username,token,authority);
        return null;
}

自定义加密类

package security.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import security.utils.Md5Utils;
/**
 * 密码加密、比对
 */
@Component // bean
@Slf4j
public class DefaultPwdEndoder implements PasswordEncoder {
    /**
     * 加密
     * @param charSequence
     * @return
     */
    @Override
    public String encode(CharSequence charSequence) {
        log.info("==== encode ====");
        log.info("charSequence 为 {}",charSequence);
        log.info("charSequence md5为 {}",Md5Utils.md5(charSequence.toString()));
        return Md5Utils.md5(charSequence.toString());
    }
     * 进行密码比对
     * @param charSequence 不加密
     * @param encodePwd  加密
    public boolean matches(CharSequence charSequence, String encodePwd) {
        log.info("==== matches ====");
        log.info("charSequence:{}",charSequence);
        log.info("charSequenceMd5:{}",Md5Utils.md5(charSequence.toString()));
        log.info("encodePwd:{}",encodePwd);
        return encodePwd.equalsIgnoreCase(Md5Utils.md5(charSequence.toString()));
}

配置UserDetailService

package security.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
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.Component;
import org.springframework.stereotype.Service;
import security.mapper.UserMapper;
import security.vo.SecurityUser;
import security.vo.User;
import java.util.Arrays;
import java.util.List;
/**
 * security 登录信息和权限获取类
 */
@Service("userDetailsService")
@Slf4j
public class UserDetailService implements UserDetailsService {
    // 注入Usermapper
    @Autowired
    private UserMapper userMapper;
    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        log.info("====== loadUserByUsername ======");
        // 通过username查询数据库获取用户信息
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("username",userName);
        User user = userMapper.selectOne(userQueryWrapper);
        // 判断用户是否存在
        if(user == null){
            throw new UsernameNotFoundException("账户信息不存在!");
        }
        // 存在对应的用户信息,则将其封装,丢给security自己去解析
        log.info("user:{}",user);
        // 权限暂时不查数据库
        List<String> admin = Arrays.asList("ROLE_user,ROLE_admin,admin");
        // 将数据封装给 SecurityUser ,因为 SecurityUser 是 UserDetails 的子类
        SecurityUser securityUser = new SecurityUser();
        securityUser.setPermissionValueList(admin);
        securityUser.setUser(user);
        log.info("securityUser:{}",securityUser.toString());
        return securityUser;
    }
}

配置数据库User对象映射类

package security.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
    private static final long serialVersionUID = -5461108964440966122L;
    private Integer id;
    private String username;
    private String password;
    private Integer enabled;
    private Integer locked;
}

配置UserDetailService使用的SecurityUser类

package security.vo;

import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
 * UserDetailService 使用该类,该类必须是 UserDetails 的子类
 */
@Data
public class SecurityUser implements UserDetails {
    // 登录用户的基本信息
    private User user;
    //当前权限
    private List<String> permissionValueList;
    public SecurityUser() {
    }
    public SecurityUser(User user) {
        if (user != null) {
            this.user = user;
        }
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        permissionValueList.forEach(permission ->{
            if(!StringUtils.isEmpty(permission)){
                SimpleGrantedAuthority authority = new SimpleGrantedAuthority(permission);
                authorities.add(authority);
            }
        });
        return authorities;
    public String getPassword() {
        return user.getPassword();
    public String getUsername() {
        return user.getUsername();
    public boolean isAccountNonExpired() {
        return true;
    public boolean isAccountNonLocked() {
    public boolean isCredentialsNonExpired() {
    public boolean isEnabled() {
}

配置mybatis-plus

首先,需要配置application.properties数据库连接源。

spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://106.55.137.66:3306/security?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

server.port=80

其次,需要配置Mapper类,查询数据库获取基本数据信息。

package security.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;
import security.vo.User;
@Repository
public interface UserMapper extends BaseMapper<User> {
}

配置security配置类

package security.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import security.config.handler.*;
import security.filter.TokenAuthFilter;
import security.filter.TokenLoginFilter;
import security.service.UserDetailService;
/**
 * security 配置类
 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)  // 方法增加权限
public class MyTokenSecurityConfig extends WebSecurityConfigurerAdapter {
    // 将 UserDetailService 注入,使其去查询数据库
    @Autowired
    private UserDetailService userDetailsService;
    // token 生成器
    @Autowired
    private TokenJwtManager tokenManager;
    // 自定义密码加密解密
    @Autowired
    private DefaultPwdEndoder defaultPwdEndoder;
    // 未登录handler
    @Autowired
    private MyUnAuthEntryPoint myUnAuthEntryPoint;
    // 无权限
    @Autowired
    private MyAccessDeniedHandler myAccessDeniedHandler;
    //  登出handler处理
    @Autowired
    private MyLogoutHandler myLogoutHandler;
    // 登录失败
    @Autowired
    private LoginFailedHandler loginFailedHandler;
    // 登录成功
    @Autowired
    private LoginSuccessHandler loginSuccessHandler;
    /**
     * 登录时,从数据库获取基本信息和权限信息
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 设置 userDetailsService 和 密码解析
        auth.userDetailsService(userDetailsService).passwordEncoder(defaultPwdEndoder);
    }
    /**
     * 配置访问过滤
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling()
                .authenticationEntryPoint(myUnAuthEntryPoint) // 未登录 handler
                .accessDeniedHandler(myAccessDeniedHandler) // 无权限
                .and().csrf().disable() // 关闭 csrf 跨域请求
                .formLogin()
                .loginProcessingUrl("/user/login")  // 设定登录请求接口
                .usernameParameter("userName")
                .passwordParameter("passWord")
                //.successHandler(loginSuccessHandler) // 因为有了 TokenLoginFilter 配置过滤器,此处配置没用
                //.failureHandler(loginFailedHandler) // 因为有了 TokenLoginFilter 配置过滤器,此处配置没用
                .permitAll()
                .and()
                .authorizeRequests() // 请求设置
                .antMatchers("/test").permitAll() // 配置不需要认证的接口
                .anyRequest().authenticated() // 任何请求都需要认证
                .and()
                .logout() // logout设定
                .logoutUrl("/logouts")  //退出请求  /logouts 未定义,交给自定义handler实现功能
                .addLogoutHandler(myLogoutHandler) // 登出 myLogoutHandler 处理
                .and()
                .addFilter(new TokenLoginFilter(tokenManager,authenticationManager())) // 认证交给 自定义 TokenLoginFilter 实现
                .addFilter(new TokenAuthFilter(authenticationManager(),tokenManager))
                .httpBasic();
    }
    /**
     * 配置不需要验证的访问路径
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        //web.ignoring().antMatchers("/test","/user/login");
        web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
    }
}

配置几个测试接口

package security.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
    @RequestMapping("/test")
    public String test(){
        return "不需要认证就能访问";
    }
}
package security.controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
    @RequestMapping("/user/test1")
    @PreAuthorize("hasAnyAuthority('admin','user')")
    public String test1(){
        return "需要认证的 /user/test1";
    }
    @RequestMapping("/user/test2")
    @PreAuthorize("hasAnyAuthority('test')")
    public String test2(){
        return "需要认证的 /user/test2";
}

Md5加密工具类

package security.utils;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
/**
 * 加密工具类
 */
public class Md5Utils {
    public static String md5(String str) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(str.getBytes());
            byte b[] = md.digest();
            str = byteToStr(b);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str;
    }
    public static String byteToStr(byte[] b){
        int i;
        StringBuffer buf = new StringBuffer("");
        for (int offset = 0; offset < b.length; offset++) {
            i = b[offset];
            //System.out.println(i);
            if (i < 0)
                i += 256;
            if (i < 16)
                buf.append("0");
            buf.append(Integer.toHexString(i));
        return buf.toString();
    /**
     * 传入文本内容,返回 SHA-256 串
     *
     * @param strText
     * @return
     */
    public static String SHA256(final String strText)
    {
        return SHA(strText, "SHA-256");
    public static String SHA1(final String strText)
        return SHA(strText, "SHA-1");
     * 传入文本内容,返回 SHA-512 串
    public static String SHA512(final String strText)
        return SHA(strText, "SHA-512");
     * 字符串 SHA 加密
    private static String SHA(final String strText, final String strType)
        // 返回值
        String strResult = null;
        // 是否是有效字符串
        if (strText != null && strText.length() > 0)
        {
            try
            {
                // SHA 加密开始
                MessageDigest messageDigest = MessageDigest.getInstance(strType);
                // 传入要加密的字符串
                messageDigest.update(strText.getBytes("utf-8"));
                // 得到 byte 类型的结果
                byte byteBuffer[] = messageDigest.digest();
                strResult = byteToStr(byteBuffer);
            }
            catch (NoSuchAlgorithmException e)
                e.printStackTrace();
            }catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
        return strResult;
    public static String base64(String str){
        String baseStr = null;
        Base64.Encoder encoder = Base64.getEncoder();
        byte[] textByte;
            textByte = str.getBytes("UTF-8");
            baseStr = encoder.encodeToString(textByte);
        } catch (UnsupportedEncodingException e) {
        return baseStr;
    public static void main(String[] args) {
        String password = "bunana1";
        System.out.println(md5(password));
        //String base64 = base64(sha512);
        //System.out.println(base64);
        //String pwd1 = md5(base64);
        //System.out.println(pwd1);
}

测试

测试采取ApiPost 工具,让测试更接近前后分离。

首先测试登录

Post
localhost/user/login

账号密码有一个不对时。

在这里插入图片描述

正确的账号密码

在这里插入图片描述

测试存在权限的接口

localhost/user/test1

在这里插入图片描述

测试不存在权限的接口

localhost/user/test2

在这里插入图片描述

测试登出

localhost/logouts

在这里插入图片描述

测试不需要权限的接口

localhost/test

在这里插入图片描述

数据库sql脚本

CREATE TABLE `user` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, -- 主键
  `username` varchar(255) DEFAULT NULL,    -- 用户名
  `password` varchar(255) DEFAULT NULL,    -- 用户密码
  `enabled` tinyint(1) DEFAULT '1',        -- 是否启用 1-启用 0-未启用
  `locked` tinyint(1) DEFAULT '0',         -- 是否被锁 1-已锁 0-未锁
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

数据为:

insert INTO user(username,password,enabled,locked) VALUES("xiangjiaoSS","1babad058e03c5296a94a5a8d7d6dd8a",1,0); -- bunana 的md5 值
insert INTO user(username,password,enabled,locked) VALUES("xiangjiaoSS2","0b13310f8db2dc22e7ddd0cdc5f0a61a",1,0); -- bunana1 的md5 值
insert INTO user(username,password,enabled,locked) VALUES("xiangjiaoSS3","b3fbcd9c9d97e47f263a19a0e01efc7d",1,0); -- bunana2 的md5 值

在这里插入图片描述

代码下载

springboot-security-10-qianhou

gitee 代码下载地址

到此这篇关于Spring Security前后分离校验token的文章就介绍到这了,更多相关Spring Security校验token内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring Native 基础环境搭建过程

    Spring Native 基础环境搭建过程

    Spring Native可以通过GraalVM将Spring应用程序编译成原生镜像,提供了一种新的方式来部署Spring应用,本文介绍Spring Native基础环境搭建,感兴趣的朋友跟随小编一起看看吧
    2024-02-02
  • Java 中如何使用 JavaFx 库标注文本颜色

    Java 中如何使用 JavaFx 库标注文本颜色

    这篇文章主要介绍了在 Java 中用 JavaFx 库标注文本颜色,在本文中,我们将了解如何更改标签的文本颜色,并且我们还将看到一个必要的示例和适当的解释,以便更容易理解该主题,需要的朋友可以参考下
    2023-05-05
  • Java枚举与注解的创建步骤

    Java枚举与注解的创建步骤

    这篇文章通过抽象的概念和具体实现步骤,充分说明了java枚举与注解的概念和使用方法,通过该篇文章你可以学会如何自定义枚举类和了解部分Java内置注解,希望对你有所帮助
    2021-06-06
  • SpringCloud zookeeper作为注册中心使用介绍

    SpringCloud zookeeper作为注册中心使用介绍

    ZooKeeper由雅虎研究院开发,是Google Chubby的开源实现,后来托管到Apache,于2010年11月正式成为Apache的顶级项目。ZooKeeper是一个经典的分布式数据一致性解决方案,致力于为分布式应用提供一个高性能、高可用,且具有严格顺序访问控制能力的分布式协调服务
    2022-11-11
  • java实现的新浪微博分享代码实例

    java实现的新浪微博分享代码实例

    这篇文章主要介绍了java实现的新浪微博分享代码实例,是通过新浪API获得授权,然后接受客户端请求的数据,第三方应用发送请求消息到微博,唤起微博分享界面,非常的实用,有相同需要的小伙伴可以参考下。
    2015-03-03
  • 23种设计模式(18)java备忘录模式

    23种设计模式(18)java备忘录模式

    这篇文章主要为大家详细介绍了23种设计模式之java备忘录模式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • 如何为Spring Cloud Gateway加上全局过滤器

    如何为Spring Cloud Gateway加上全局过滤器

    这篇文章主要介绍了如何为Spring Cloud Gateway加上全局过滤器,帮助大家更好得理解和学习使用Gateway,感兴趣的朋友可以了解下
    2021-03-03
  • Jenkins自动部署Net Core过程图解

    Jenkins自动部署Net Core过程图解

    这篇文章主要介绍了Jenkins自动部署Net Core过程图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-12-12
  • Java获取登录用户的IP地址示例代码

    Java获取登录用户的IP地址示例代码

    在开发中我们经常需要获取用户IP地址,通过地址来实现一些功能,下面这篇文章主要给大家介绍了关于Java获取登录用户的IP地址的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-05-05
  • Struts2 使用OGNL遍历map方法详解

    Struts2 使用OGNL遍历map方法详解

    这篇文章主要介绍了Struts2 使用OGNL遍历map方法详解,具有一定参考价值,需要的朋友可以了解下。
    2017-09-09

最新评论