Spring?Security前后分離校驗(yàn)token的實(shí)現(xiàn)方法
前言
之前采取項(xiàng)目中嵌套html
頁面,實(shí)現(xiàn)基本的登錄校驗(yàn)
、權(quán)限校驗(yàn)
、登出操作
、記住我
等功能試下。
但是,現(xiàn)在的開發(fā)基本都是前后分離
樣式,后端并不需要配置登錄頁
的操作。
如何才能做到前后分離
,同時(shí)也能支持登錄
和token
校驗(yàn)?zāi)?,本篇博客詳?xì)說明。
token配置
本次token
生成采取jwt
的方式。
引入JWT依賴文件
<dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.10.3</version> </dependency>
配置token管理器類
自定一個(gè)Token生成和從token中解析用戶名的一個(gè)類,并交給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 { // 設(shè)置token時(shí)間 private int tokenEcpiration = 24*60*60*1000; // 毫秒 24h // 編碼密鑰 private String tokenSignKey = "123456"; // 1、根據(jù)用戶名生成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()) // 過期時(shí)間 .sign(Algorithm.HMAC256(tokenSignKey));// 簽名 return userName1; } // 2、根據(jù)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<>(); // 保存數(shù)據(jù) resultMap.put("code","10000"); resultMap.put("msg","當(dāng)前賬戶未登錄"); resultMap.put("data",new HashMap<>()); // 設(shè)置返回消息類型 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(); } }
配置無權(quán)限處理類
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; /** * 無權(quán)訪問配置(前后分離) */ @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<>(); // 保存數(shù)據(jù) resultMap.put("code","403"); resultMap.put("msg","無權(quán)訪問"); resultMap.put("data",null); // 設(shè)置返回消息類型 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<>(); // 保存數(shù)據(jù) resultMap.put("code","200"); resultMap.put("msg",userName+"登錄成功"); resultMap.put("data",new HashMap<>()); // 設(shè)置返回消息類型 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認(rèn)證過濾器
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管理會(huì)報(bào)錯(cuò) @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); // 關(guān)閉登錄只允許 post // 設(shè)置登陸路徑,并且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、認(rèn)證成功調(diào)用 @Autowired protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { log.info("==== successfulAuthentication ======"); // 認(rèn)證成功之后,獲取認(rèn)證后的用戶基本信息 SecurityUser securityUser = (SecurityUser) authResult.getPrincipal(); // 根據(jù)用戶名生成對應(yīng)的token String token = tokenJwtManager.createToken(securityUser.getUsername()); // token信息存于redis、數(shù)據(jù)庫、緩存等 // 返回成功 Map<String,Object> resultMap = new HashMap<>(); // 保存數(shù)據(jù) resultMap.put("code","200"); resultMap.put("msg","登錄成功"); resultMap.put("data",token); // 設(shè)置返回消息類型 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、認(rèn)證失敗調(diào)用的方法 protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) log.info("==== unsuccessfulAuthentication ======"); resultMap.put("code","500"); resultMap.put("msg","登錄驗(yàn)證失敗"); resultMap.put("data",new HashMap<>()); }
配置token權(quán)限校驗(yàn)過濾器
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 校驗(yàn) */ @Slf4j //@Component // 交給 spring 會(huì)報(bào)錯(cuò) 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校驗(yàn)"); //獲取當(dāng)前認(rèn)證成功用戶權(quán)限信息 UsernamePasswordAuthenticationToken authRequest = getAuthentication(request); if(authRequest != null){ // 有權(quán)限,則放入權(quán)限上下文中 SecurityContextHolder.getContext().setAuthentication(authRequest); } // 執(zhí)行下一個(gè) 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); // 數(shù)據(jù)庫獲取權(quán)限信息 // 本次模擬 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()); } * 進(jìn)行密碼比對 * @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 登錄信息和權(quán)限獲取類 */ @Service("userDetailsService") @Slf4j public class UserDetailService implements UserDetailsService { // 注入U(xiǎn)sermapper @Autowired private UserMapper userMapper; @Override public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException { log.info("====== loadUserByUsername ======"); // 通過username查詢數(shù)據(jù)庫獲取用戶信息 QueryWrapper<User> userQueryWrapper = new QueryWrapper<>(); userQueryWrapper.eq("username",userName); User user = userMapper.selectOne(userQueryWrapper); // 判斷用戶是否存在 if(user == null){ throw new UsernameNotFoundException("賬戶信息不存在!"); } // 存在對應(yīng)的用戶信息,則將其封裝,丟給security自己去解析 log.info("user:{}",user); // 權(quán)限暫時(shí)不查數(shù)據(jù)庫 List<String> admin = Arrays.asList("ROLE_user,ROLE_admin,admin"); // 將數(shù)據(jù)封裝給 SecurityUser ,因?yàn)?SecurityUser 是 UserDetails 的子類 SecurityUser securityUser = new SecurityUser(); securityUser.setPermissionValueList(admin); securityUser.setUser(user); log.info("securityUser:{}",securityUser.toString()); return securityUser; } }
配置數(shù)據(jù)庫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; //當(dāng)前權(quán)限 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
數(shù)據(jù)庫連接源。
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類,查詢數(shù)據(jù)庫獲取基本數(shù)據(jù)信息。
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) // 方法增加權(quán)限 public class MyTokenSecurityConfig extends WebSecurityConfigurerAdapter { // 將 UserDetailService 注入,使其去查詢數(shù)據(jù)庫 @Autowired private UserDetailService userDetailsService; // token 生成器 @Autowired private TokenJwtManager tokenManager; // 自定義密碼加密解密 @Autowired private DefaultPwdEndoder defaultPwdEndoder; // 未登錄handler @Autowired private MyUnAuthEntryPoint myUnAuthEntryPoint; // 無權(quán)限 @Autowired private MyAccessDeniedHandler myAccessDeniedHandler; // 登出handler處理 @Autowired private MyLogoutHandler myLogoutHandler; // 登錄失敗 @Autowired private LoginFailedHandler loginFailedHandler; // 登錄成功 @Autowired private LoginSuccessHandler loginSuccessHandler; /** * 登錄時(shí),從數(shù)據(jù)庫獲取基本信息和權(quán)限信息 * @param auth * @throws Exception */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 設(shè)置 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) // 無權(quán)限 .and().csrf().disable() // 關(guān)閉 csrf 跨域請求 .formLogin() .loginProcessingUrl("/user/login") // 設(shè)定登錄請求接口 .usernameParameter("userName") .passwordParameter("passWord") //.successHandler(loginSuccessHandler) // 因?yàn)橛辛?TokenLoginFilter 配置過濾器,此處配置沒用 //.failureHandler(loginFailedHandler) // 因?yàn)橛辛?TokenLoginFilter 配置過濾器,此處配置沒用 .permitAll() .and() .authorizeRequests() // 請求設(shè)置 .antMatchers("/test").permitAll() // 配置不需要認(rèn)證的接口 .anyRequest().authenticated() // 任何請求都需要認(rèn)證 .and() .logout() // logout設(shè)定 .logoutUrl("/logouts") //退出請求 /logouts 未定義,交給自定義handler實(shí)現(xiàn)功能 .addLogoutHandler(myLogoutHandler) // 登出 myLogoutHandler 處理 .and() .addFilter(new TokenLoginFilter(tokenManager,authenticationManager())) // 認(rèn)證交給 自定義 TokenLoginFilter 實(shí)現(xiàn) .addFilter(new TokenAuthFilter(authenticationManager(),tokenManager)) .httpBasic(); } /** * 配置不需要驗(yàn)證的訪問路徑 * @param web * @throws Exception */ @Override public void configure(WebSecurity web) throws Exception { //web.ignoring().antMatchers("/test","/user/login"); web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**"); } }
配置幾個(gè)測試接口
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 "不需要認(rèn)證就能訪問"; } }
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 "需要認(rèn)證的 /user/test1"; } @RequestMapping("/user/test2") @PreAuthorize("hasAnyAuthority('test')") public String test2(){ return "需要認(rèn)證的 /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(); /** * 傳入文本內(nèi)容,返回 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"); * 傳入文本內(nèi)容,返回 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 類型的結(jié)果 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
賬號(hào)密碼有一個(gè)不對時(shí)。
正確的賬號(hào)密碼
測試存在權(quán)限的接口
localhost/user/test1
測試不存在權(quán)限的接口
localhost/user/test2
測試登出
localhost/logouts
測試不需要權(quán)限的接口
localhost/test
數(shù)據(jù)庫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;
數(shù)據(jù)為:
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
到此這篇關(guān)于Spring Security前后分離校驗(yàn)token的文章就介紹到這了,更多相關(guān)Spring Security校驗(yàn)token內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java使用wait/notify實(shí)現(xiàn)線程間通信上篇
wait()和notify()是直接隸屬于Object類,也就是說所有對象都擁有這一對方法,下面這篇文章主要給大家介紹了關(guān)于使用wait/notify實(shí)現(xiàn)線程間通信的相關(guān)資料,需要的朋友可以參考下2022-12-12Java手把手必會(huì)的實(shí)例漢諾塔講解練習(xí)
漢諾塔,傳說神在創(chuàng)造世界的時(shí)候做了三根金剛石柱子,并在一個(gè)教塔里留下了三根金剛石棒,第一根上面從上到下套著64個(gè)按從小到大排列的金盤,神命令廟里的眾僧將它們一個(gè)個(gè)地從這根金剛石棒搬到另一根金剛石棒上,大盤不能放在小盤上。最后64個(gè)金盤仍然要按從小到大排列2021-09-09Java基于Calendar類輸出指定年份和月份的日歷代碼實(shí)例
這篇文章主要介紹了Java 使用Calendar類輸出指定年份和月份的日歷,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02基于Spring AOP @AspectJ進(jìn)階說明
這篇文章主要介紹了基于Spring AOP @AspectJ進(jìn)階說明,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-01-01關(guān)于Java?float和double精度范圍大小
這篇文章主要介紹了關(guān)于Java?float和double精度范圍大小,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12Java實(shí)現(xiàn)發(fā)送郵件功能時(shí)碰到的坑
之前用163郵箱發(fā)郵件時(shí)明明是成功的,但是使用中國移動(dòng)自己的郵箱時(shí),無論如何在linux服務(wù)器中都發(fā)送不成功。下面小編給大家說下我是怎么解決的,一起看下吧2016-06-06基于swagger參數(shù)與實(shí)體中參數(shù)不一致的原因分析
這篇文章主要介紹了基于swagger參數(shù)與實(shí)體中參數(shù)不一致的原因分析,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11