今天主要介紹以下內(nèi)容:
今日內(nèi)容介紹,大約花費(fèi)40分鐘
圖片
下圖顯示了我們?nèi)绾螌?shí)現(xiàn)用戶注冊(cè)、用戶登錄和授權(quán)流程的流程。
圖片
如果客戶端訪問(wèn)受保護(hù)的資源,則必須將合法的 JWT 添加到 HTTP 授權(quán)標(biāo)頭中。
您可以通過(guò)下圖概述我們的Spring Boot項(xiàng)目:
圖片
Spring Security介紹:
注意:WebSecurityConfigurerAdapter 從 SpringBoot 2.7.0 開(kāi)始被棄用)
下圖是Spring Boot項(xiàng)目的文件夾和文件結(jié)構(gòu):
圖片
圖片
根據(jù)Sql創(chuàng)建表,表間關(guān)系如下:
圖片
SET FOREIGN_KEY_CHECKS=0;-- ------------------------------ Table structure for pe_permission-- ----------------------------DROP TABLE IF EXISTS `pe_permission`;CREATE TABLE `pe_permission` ( `id` varchar(40) NOT NULL COMMENT '主鍵', `name` varchar(255) DEFAULT NULL COMMENT '權(quán)限名稱', `code` varchar(20) DEFAULT NULL, `description` text COMMENT '權(quán)限描述', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;-- ------------------------------ Records of pe_permission-- ----------------------------INSERT INTO `pe_permission` VALUES ('1', '添加用戶', 'user-add', null);INSERT INTO `pe_permission` VALUES ('2', '查詢用戶', 'user-find', null);INSERT INTO `pe_permission` VALUES ('3', '更新用戶', 'user-update', null);INSERT INTO `pe_permission` VALUES ('4', '刪除用戶', 'user-delete', null);-- ------------------------------ Table structure for pe_role-- ----------------------------DROP TABLE IF EXISTS `pe_role`;CREATE TABLE `pe_role` ( `id` varchar(40) NOT NULL COMMENT '主鍵ID', `name` varchar(40) DEFAULT NULL COMMENT '權(quán)限名稱', `description` varchar(255) DEFAULT NULL COMMENT '說(shuō)明', PRIMARY KEY (`id`), UNIQUE KEY `UK_k3beff7qglfn58qsf2yvbg41i` (`name`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;-- ------------------------------ Records of pe_role-- ----------------------------INSERT INTO `pe_role` VALUES ('1', '系統(tǒng)管理員', '系統(tǒng)日常維護(hù)');INSERT INTO `pe_role` VALUES ('2', '普通員工', '普通操作權(quán)限');-- ------------------------------ Table structure for pe_role_permission-- ----------------------------DROP TABLE IF EXISTS `pe_role_permission`;CREATE TABLE `pe_role_permission` ( `role_id` varchar(40) NOT NULL COMMENT '角色I(xiàn)D', `permission_id` varchar(40) NOT NULL COMMENT '權(quán)限ID', PRIMARY KEY (`role_id`,`permission_id`), KEY `FK74qx7rkbtq2wqms78gljv87a0` (`permission_id`), KEY `FKee9dk0vg99shvsytflym6egxd` (`role_id`), CONSTRAINT `fk-p-rid` FOREIGN KEY (`role_id`) REFERENCES `pe_role` (`id`), CONSTRAINT `fk-pid` FOREIGN KEY (`permission_id`) REFERENCES `pe_permission` (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;-- ------------------------------ Records of pe_role_permission-- ----------------------------INSERT INTO `pe_role_permission` VALUES ('1', '1');INSERT INTO `pe_role_permission` VALUES ('1', '2');INSERT INTO `pe_role_permission` VALUES ('2', '2');INSERT INTO `pe_role_permission` VALUES ('1', '3');INSERT INTO `pe_role_permission` VALUES ('1', '4');-- ------------------------------ Table structure for pe_user-- ----------------------------DROP TABLE IF EXISTS `pe_user`;CREATE TABLE `pe_user` ( `id` varchar(40) NOT NULL COMMENT 'ID', `username` varchar(255) NOT NULL COMMENT '用戶名稱', `password` varchar(255) DEFAULT NULL COMMENT '密碼', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;-- ------------------------------ Records of pe_user-- ----------------------------INSERT INTO `pe_user` VALUES ('1', 'zhangsan', '$2a$10$.fXoccJHJkb9KM1FYJd1Ve.2P0B0RgLvloBDPwGjRxcP2obt2NRkG');INSERT INTO `pe_user` VALUES ('2', 'lisi', '$2a$10$.fXoccJHJkb9KM1FYJd1Ve.2P0B0RgLvloBDPwGjRxcP2obt2NRkG');INSERT INTO `pe_user` VALUES ('3', 'wangwu', '$2a$10$.fXoccJHJkb9KM1FYJd1Ve.2P0B0RgLvloBDPwGjRxcP2obt2NRkG');-- ------------------------------ Table structure for pe_user_role-- ----------------------------DROP TABLE IF EXISTS `pe_user_role`;CREATE TABLE `pe_user_role` ( `role_id` varchar(40) NOT NULL COMMENT '角色I(xiàn)D', `user_id` varchar(40) NOT NULL COMMENT '權(quán)限ID', KEY `FK74qx7rkbtq2wqms78gljv87a1` (`role_id`), KEY `FKee9dk0vg99shvsytflym6egx1` (`user_id`), CONSTRAINT `fk-rid` FOREIGN KEY (`role_id`) REFERENCES `pe_role` (`id`), CONSTRAINT `fk-uid` FOREIGN KEY (`user_id`) REFERENCES `pe_user` (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;-- ------------------------------ Records of pe_user_role-- ----------------------------INSERT INTO `pe_user_role` VALUES ('1', '1');
<?xml versinotallow="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <artifactId>spring-boot-starter-parent</artifactId> <groupId>org.springframework.boot</groupId> <version>2.7.15</version> </parent> <groupId>com.zbbmeta</groupId> <artifactId>spring-boot-backend-example</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.30</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.20</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-configuration-processor --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> </dependencies></project>
安裝MyBatisX插件,這里就不過(guò)多介紹如何安裝插件了,和其他插件安裝相同 表生成代碼步驟如下:
圖片
圖片
圖片
Spring Security 將加載用戶詳細(xì)信息以執(zhí)行身份驗(yàn)證和授權(quán)。所以它有 UserDetailsService 我們需要實(shí)現(xiàn)的接口。
在com.zbbmeta.service.impl包下創(chuàng)建UserDetailsService實(shí)現(xiàn)類UserDetailsServiceImpl
@Servicepublic class UserDetailsServiceImpl implements UserDetailsService { @Autowired private UserService userService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userService.findByName(username); List<Role> roles = user.getRoles(); List<String> authorities = new ArrayList<>(); for (Role role : roles) { List<Permission> permissions = role.getPermissions(); List<String> collect = permissions.stream().map(x -> x.getCode()).distinct().collect(Collectors.toList()); authorities.addAll(collect); } List<String> collect1 = authorities.stream().distinct().collect(Collectors.toList()); return new org.springframework.security.core.userdetails.User(username, user.getPassword(), AuthorityUtils.createAuthorityList(collect1.toString())); }}
public interface UserMapper extends BaseMapper<User> { User findByUsername(String name);}
在User實(shí)體類中添加字段roles
@TableField(exist = false) private List<Role> roles = new ArrayList<>();//用戶與角色 多對(duì)多
圖片
并且在resultMap添加一對(duì)多根據(jù)用戶查詢對(duì)應(yīng)角色
<?xml versinotallow="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.zbbmeta.mapper.UserMapper"> <resultMap id="BaseResultMap" type="com.zbbmeta.entity.User"> <id property="id" column="id" jdbcType="VARCHAR"/> <result property="username" column="username" jdbcType="VARCHAR"/> <result property="password" column="password" jdbcType="VARCHAR"/> <!--一對(duì)多映射用這個(gè) ofTyp是一對(duì)多的集合的所存放的實(shí)體類 javaType實(shí)體類的屬性類型--> <collection property="roles" ofType="com.zbbmeta.entity.Role" select="com.zbbmeta.mapper.RoleMapper.queryRoleListByUserId" column="id"> <id property="id" column="id" jdbcType="VARCHAR"/> <result property="name" column="name" jdbcType="VARCHAR"/> <result property="description" column="description" jdbcType="VARCHAR"/> </collection> </resultMap> <sql id="Base_Column_List"> id,username,password </sql> <select id="findByUsername" resultMap="BaseResultMap"> select * from pe_user where username=#{name}; </select></mapper>
public interface RoleMapper extends BaseMapper<Role> { List<Role> queryRoleListByUserId(@Param("id") Long id);}
@TableField(exist = false) private List<Permission> permissions = new ArrayList<>();//用戶與角色 多對(duì)多
圖片
并且在resultMap添加一對(duì)多根據(jù)角色查詢對(duì)應(yīng)權(quán)限
<?xml versinotallow="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.zbbmeta.mapper.RoleMapper"> <resultMap id="BaseResultMap" type="com.zbbmeta.entity.Role"> <id property="id" column="id" jdbcType="VARCHAR"/> <result property="name" column="name" jdbcType="VARCHAR"/> <result property="description" column="description" jdbcType="VARCHAR"/> <collection property="permissions" ofType="com.zbbmeta.entity.Permission" select="com.zbbmeta.mapper.PermissionMapper.queryPermissionList" column="id"> <id property="id" column="id" jdbcType="VARCHAR"/> <result property="name" column="name" jdbcType="VARCHAR"/> <result property="code" column="code" jdbcType="VARCHAR"/> <result property="description" column="description" jdbcType="VARCHAR"/> </collection> </resultMap> <sql id="Base_Column_List"> id,name,description </sql> <select id="queryRoleListByUserId" resultMap="BaseResultMap"> select distinct pr.* from pe_user_role pur inner join pe_role pr on pur.role_id =pr.id where pur.user_id =#{id} </select></mapper>
public interface PermissionMapper extends BaseMapper<Permission> { List<Permission> queryPermissionList(@Param("id") Long id);}
<?xml versinotallow="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.zbbmeta.mapper.PermissionMapper"> <resultMap id="BaseResultMap" type="com.zbbmeta.entity.Permission"> <id property="id" column="id" jdbcType="VARCHAR"/> <result property="name" column="name" jdbcType="VARCHAR"/> <result property="code" column="code" jdbcType="VARCHAR"/> <result property="description" column="description" jdbcType="VARCHAR"/> </resultMap> <sql id="Base_Column_List"> id,name,code, description </sql> <select id="queryPermissionList" resultType="com.zbbmeta.entity.Permission"> select * from pe_permission pp inner join pe_role_permission prp on pp.id = prp.permission_id where prp.role_id=#{id} </select></mapper>
注意:不使用 WebSecurityConfigurerAdapter,因?yàn)閃ebSecurityConfigurerAdapter 從 Spring 2.7.0 中棄用
jwt: config: key: zbbmeta ttl: 3600
在com.zbbmeta.util包下創(chuàng)建JwtUtil類
package com.zbbmeta.util;import io.jsonwebtoken.*;import lombok.Data;import org.junit.platform.commons.logging.Logger;import org.junit.platform.commons.logging.LoggerFactory;import org.springframework.beans.factory.annotation.Value;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.security.core.Authentication;import org.springframework.stereotype.Component;import java.util.Date;import java.util.Map;/** * @author springboot葵花寶典 * @description: TODO */@Component@ConfigurationProperties("jwt.config")@Datapublic class JwtUtil { private String key; private long ttl; public String createJwt(String id, String subject, Map<String,Object> map){ long now = System.currentTimeMillis(); long exp = now+ttl*1000; JwtBuilder jwtBuilder =null; try { jwtBuilder = Jwts.builder().setId(id) .setSubject(subject) .setIssuedAt(new Date()) .signWith(SignatureAlgorithm.HS256, key); for (Map.Entry<String, Object> stringObjectEntry : map.entrySet()) { jwtBuilder.claim(stringObjectEntry.getKey(), stringObjectEntry.getValue()); } if (ttl > 0) { jwtBuilder.setExpiration(new Date(exp)); } }catch (Exception e){ System.err.println(e.getMessage()); } return jwtBuilder.compact(); } public Claims parseJWT(String token){ Claims claims = Jwts.parser() .setSigningKey(key) .parseClaimsJws(token).getBody(); return claims; }}
WebSecurityConfig類 是我們安全認(rèn)證的關(guān)鍵。它為受保護(hù)的資源配置 cors、csrf、會(huì)話管理、規(guī)則。
package com.zbbmeta.config;import com.zbbmeta.filter.AuthTokenFilter;import com.zbbmeta.service.impl.UserDetailsServiceImpl;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.authentication.dao.DaoAuthenticationProvider;import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;import org.springframework.security.config.http.SessionCreationPolicy;import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;import org.springframework.security.crypto.password.PasswordEncoder;import org.springframework.security.web.SecurityFilterChain;import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;/** * @author springboot葵花寶典 * @description: TODO */@Configuration@EnableWebSecuritypublic class WebSecurityConfig { @Autowired UserDetailsServiceImpl userDetailsService; @Autowired private AuthEntryPointJwt unauthorizedHandler; @Bean public AuthTokenFilter authTokenFilter() { return new AuthTokenFilter(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public DaoAuthenticationProvider authenticationProvider() { DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(); authProvider.setUserDetailsService(userDetailsService); authProvider.setPasswordEncoder(passwordEncoder()); return authProvider; } /** * 認(rèn)證 * @param http * @return * @throws Exception */ @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.cors().and().csrf().disable() .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() .authorizeRequests().antMatchers("/api/auth/**").permitAll()//不需要通過(guò)登錄驗(yàn)證就可以被訪問(wèn)的資源路徑 .anyRequest().authenticated(); http.authenticationProvider(authenticationProvider()); http.addFilterBefore(authTokenFilter(), UsernamePasswordAuthenticationFilter.class); return http.build(); }}
注: 同樣的在 Spring Security 5.8 后要把 antMatchers() 改為 requestMatchers()
在 com.zbbmeta.filter包下創(chuàng)建AuthTokenFilter類,對(duì)每個(gè)請(qǐng)求進(jìn)行過(guò)濾。 AuthTokenFilter 集成 OncePerRequestFilter 和覆蓋 doFilterInternal() 方法的類。
@Slf4jpublic class AuthTokenFilter extends OncePerRequestFilter { @Autowired private JwtUtil jwtUtil; @Autowired private UserDetailsService userDetailsService; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String requestURI = request.getRequestURI(); //登錄或者注冊(cè)放行 if(requestURI.contains("/api/auth")){ filterChain.doFilter(request, response); return ; } String authorization = request.getHeader("Authorization"); if(StrUtil.isNotBlank(authorization)){ String token = authorization.replace("Bearer ", ""); Claims claims = jwtUtil.parseJWT(token); String username = claims.get("username", String.class); UserDetails userDetails = userDetailsService.loadUserByUsername(username); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( userDetails, null, userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authentication); } filterChain.doFilter(request, response); }}
我們?cè)诶锩?doFilterInternal() 做什么:
創(chuàng)建 AuthEntryPointJwt 實(shí)現(xiàn)接口的 AuthenticationEntryPoint 類。然后我們重寫(xiě)該 commence() 方法。每當(dāng)未經(jīng)身份驗(yàn)證的用戶請(qǐng)求受保護(hù)的 HTTP 資源并 AuthenticationException 拋出時(shí),都會(huì)觸發(fā)此方法。
package com.zbbmeta.config;import com.fasterxml.jackson.databind.ObjectMapper;import lombok.extern.slf4j.Slf4j;import org.springframework.http.MediaType;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.util.HashMap;import java.util.Map;/** * @author springboot葵花寶典 * @description: TODO */@Slf4j@Componentpublic class AuthEntryPointJwt implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { log.error("Unauthorized error: {}", authException.getMessage()); response.setContentType(MediaType.APPLICATION_JSON_VALUE); response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); final Map<String, Object> body = new HashMap<>(); body.put("code", HttpServletResponse.SC_UNAUTHORIZED); body.put("message", authException.getMessage()); body.put("path", request.getServletPath()); final ObjectMapper mapper = new ObjectMapper(); mapper.writeValue(response.getOutputStream(), body); }}
package com.zbbmeta.controller;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;import com.zbbmeta.api.Result;import com.zbbmeta.api.ResultCode;import com.zbbmeta.dto.LoginDto;import com.zbbmeta.dto.SignupDto;import com.zbbmeta.entity.Permission;import com.zbbmeta.entity.Role;import com.zbbmeta.entity.User;import com.zbbmeta.entity.UserRole;import com.zbbmeta.service.RoleService;import com.zbbmeta.service.UserRoleService;import com.zbbmeta.service.UserService;import com.zbbmeta.util.JwtUtil;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.security.crypto.password.PasswordEncoder;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import java.util.*;import java.util.stream.Collectors;/** * @author springboot葵花寶典 * @description: TODO */@RequestMapping("/api/auth")@RestControllerpublic class AuthController { @Autowired UserService userService; @Autowired RoleService roleService; @Autowired UserRoleService userRoleService; @Autowired PasswordEncoder passwordEncoder; @Autowired private JwtUtil jwtUtil; @PostMapping("/signin") public Result authenticateUser(@RequestBody LoginDto loginDto) { //根據(jù)用戶名查找用戶 User user = userService.findByName(loginDto.getUsername()); //不存在表示登錄失敗 if(Objects.isNull(user)){ return Result.FAIL(ResultCode.USERNOEXIT_ERROR); } //密碼不同登錄失敗 if(!passwordEncoder.matches(loginDto.getPassword(),user.getPassword())){ return Result.FAIL(ResultCode.PASSWORD_ERROR); } List<String> collect = user.getRoles().stream().map(x -> x.getName()).collect(Collectors.toList()); StringBuilder builder = new StringBuilder(); List<Role> roles = user.getRoles(); for (Role role : roles) { List<Permission> permissions = role.getPermissions(); for (Permission permission : permissions) { builder.append(permission.getCode()).append(","); } } Map<String, Object> map = new HashMap<>(); map.put("username",user.getUsername()); map.put("permission",builder); String token = jwtUtil.createJwt(user.getId(), user.getUsername(), map); return Result.SUCCESS(token); } /** * 用戶注冊(cè) * @param signupDto * @return */ @PostMapping("/signup") public Result registerUser( @RequestBody SignupDto signupDto){ //根據(jù)用戶名獲取用戶 User user = userService.findByName(signupDto.getUsername()); //用戶不是null表示用戶已經(jīng)存在 if(Objects.nonNull(user)){ return Result.FAIL(ResultCode.USER_ERROR); } //添加用戶 User user1 = new User(); user1.setUsername(signupDto.getUsername()); user1.setPassword(signupDto.getPassword()); user1.setPassword(passwordEncoder.encode(signupDto.getPassword())); List<String> strRoles = signupDto.getRole(); List<Role> roles = new ArrayList<>(); //如果沒(méi)有用戶角色,默認(rèn)添加普通員工 if (strRoles == null) { LambdaQueryWrapper<Role> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Role::getName,"普通員工"); Role role = roleService.getOne(wrapper); roles.add(role); }else { strRoles.forEach(role ->{ LambdaQueryWrapper<Role> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Role::getName,role); Role adminRole = roleService.getOne(wrapper); roles.add(adminRole); }); } //添加用戶信息 boolean save = userService.save(user1); String id = user1.getId(); List<UserRole> userRolesList = new ArrayList<>(); for (Role role : roles) { UserRole userRoles = new UserRole(); userRoles.setUserId(id); userRoles.setRoleId(role.getId()); userRolesList.add(userRoles); } //添加用戶和角色關(guān)系 userRoleService.saveBatch(userRolesList); return Result.SUCCESS("注冊(cè)成功!"); }}
圖片
注冊(cè)后的pe_user表格數(shù)據(jù)如下所示:
圖片
圖片
因?yàn)槲覀儧](méi)有登錄,所以受保護(hù)的資源不能訪問(wèn)
圖片
圖片
今天,我們?cè)赟pring Boot示例中學(xué)到關(guān)于Spring Security和基于JWT令牌的身份驗(yàn)證的有趣知識(shí)。盡管我們寫(xiě)了很多代碼,但我希望你能理解應(yīng)用程序的整體架構(gòu),并輕松地將其應(yīng)用到你的項(xiàng)目中。
## 代碼地址https://github.com/bangbangzhou/spring-boot-backend-example.git
本文鏈接:http://www.www897cc.com/showinfo-26-40684-0.htmlSpring Boot Security + JWT Token 的簡(jiǎn)單應(yīng)用
聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com
上一篇: MySQL數(shù)據(jù)庫(kù)壓力測(cè)試與性能評(píng)估方法:Java實(shí)戰(zhàn)