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

作者:专注写bug 时间:2023-06-26 17:00:30 

前言

之前采取项目中嵌套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

账号密码有一个不对时。

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

正确的账号密码

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

测试存在权限的接口

localhost/user/test1

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

测试不存在权限的接口

localhost/user/test2

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

测试登出

localhost/logouts

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

测试不需要权限的接口

localhost/test

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

数据库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 值

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

代码下载

springboot-security-10-qianhou

gitee 代码下载地址

来源:https://blog.csdn.net/qq_38322527/article/details/123121463

标签:Spring,Security,校验,token
0
投稿

猜你喜欢

  • java 工厂模式的讲解及优缺点的介绍

    2022-02-05 10:57:09
  • javaweb学习总结——使用JDBC处理MySQL大数据

    2022-10-19 22:45:32
  • Spring boot多线程配置方法

    2022-12-14 21:02:02
  • C++函数指针详解

    2021-10-07 15:49:44
  • C#之CLR内存原理初探

    2023-02-16 00:58:09
  • C++中静态成员函数与静态成员变量(static )

    2021-11-08 07:31:38
  • C#定时关闭窗体实例

    2023-07-09 22:53:25
  • Android仿百度图片查看功能

    2023-09-26 07:50:24
  • Spring Security UserDetails实现原理详解

    2023-05-07 01:18:21
  • Android自定义顶部标题栏

    2023-02-21 19:03:47
  • 安卓自定义流程进度图控件实例代码

    2023-10-30 00:07:23
  • DataGridView实现点击列头升序和降序排序

    2022-07-31 21:54:01
  • Java下利用Jackson进行JSON解析和序列化示例

    2023-09-27 14:37:38
  • Java如何生成4位、6位随机数短信验证码(高效实现)

    2023-01-24 18:05:20
  • 聊聊SpringMVC项目依赖和静态资源导出问题

    2023-03-26 13:32:20
  • Java实现单链表反转的多种方法总结

    2023-11-11 02:28:08
  • Spring @Import注解的使用

    2022-03-26 16:38:43
  • C字符串操作函数的实现详细解析

    2022-10-26 16:28:37
  • Spring中的使用@Async异步调用方法

    2023-07-10 17:20:28
  • SpringBoot异步调用方法实现场景代码实例

    2023-10-23 14:14:23
  • asp之家 软件编程 m.aspxhome.com