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

这篇文章主要介绍了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 Security前后分离校验token的实现方法

基础教程推荐