记录学习Spring boot 整合Spring Security Jwt

学习参考 – 慢慢的干货

https://shimo.im/docs/OnZDwoxFFL8bnP1c/read

首先创建Spring Boot项目以及导入依赖

    <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.22</version></dependency><!--mybatis-plus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.3.1.tmp</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.3.1.tmp</version></dependency><dependency><groupId>org.apache.velocity</groupId><artifactId>velocity</artifactId><version>1.7</version></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--security--><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-test</artifactId><scope>test</scope></dependency><!--jwt--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency><!--hutool工具--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.5.7</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency></dependencies>

application.yml配置

# 数据库相关配置
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/securitytext?serverTimezone=GMT&characterEncoding=utf-8username: rootpassword: 1233dbcp2:test-on-borrow: truevalidation-query: SELECT 1hikari:max-lifetime: 30000servlet:multipart:max-file-size: 1024MBmax-request-size: 1024MB# mybatis-plus相关配置
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#  mapper-locations: classpath*:/mapper/**Mapper.xml# 服务端口号
server:port: 8030# jwt配置
xiaojiang:jwt:secret: f4e2e52034348f86b67cde581c0f9eb5expire: 604800header: Authorization

创建数据库

-- ----------------------------
-- Table structure for sys_user
-- ----------------------------DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户id',`username` varchar(64) DEFAULT NULL COMMENT '用户名',`password` varchar(64) DEFAULT NULL COMMENT '用户密码',`avatar` varchar(255) DEFAULT NULL COMMENT '用户头像',`email` varchar(64) DEFAULT NULL COMMENT '用户邮箱',`city` varchar(64) DEFAULT NULL COMMENT '城市',`created_time` datetime DEFAULT NULL COMMENT '用户创建时间',`updated_time` datetime DEFAULT NULL COMMENT '用户修改时间',`last_login_time` datetime DEFAULT NULL COMMENT '用户上次登录时间',`statu` int(5) NOT NULL COMMENT '用户状态 1可用|0不可用',PRIMARY KEY (`id`),UNIQUE KEY `UK_USERNAME` (`username`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES ('1', 'admin', '$2a$10$R7zegeWzOXPw871CmNuJ6upC0v8D373GuLuTw8jn6NET4BkPRZfgK', 'https://image-1300566513.cos.ap-guangzhou.myqcloud.com/upload/images/5a9f48118166308daba8b6da7e466aab.jpg', '123@qq.com', '广州', '2021-01-12 22:13:53', '2021-01-16 16:57:32', '2020-12-30 08:38:37', '1');INSERT INTO `sys_user` VALUES ('2', 'test', '$2a$10$0ilP4ZD1kLugYwLCs4pmb.ZT9cFqzOZTNaMiHxrBnVIQUGUwEvBIO', 'https://image-1300566513.cos.ap-guangzhou.myqcloud.com/upload/images/5a9f48118166308daba8b6da7e466aab.jpg', 'test@qq.com', null, '2021-01-30 08:20:22', '2021-01-30 08:55:57', null, '1');-- ----------------------------
-- Table structure for sys_role
-- ----------------------------DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '角色id',`name` varchar(64) NOT NULL COMMENT '角色名称',`code` varchar(64) NOT NULL COMMENT '角色',`created_time` datetime DEFAULT NULL COMMENT'角色创建时间',`updated_time` datetime DEFAULT NULL COMMENT '角色修改时间',`statu` int(5) NOT NULL COMMENT '角色状态 1可用|0不可用',PRIMARY KEY (`id`),UNIQUE KEY `name` (`name`) USING BTREE,UNIQUE KEY `code` (`code`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES ('1', '超级管理员', 'admin', '2021-01-16 13:29:03', '2021-01-17 15:50:45', '1');INSERT INTO `sys_role` VALUES ('2', '普通用户', 'normal', '2021-01-04 10:09:14', '2021-01-30 08:19:52', '1');-- ----------------------------
-- Table structure for sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`user_id` bigint(20) NOT NULL COMMENT '用户id',`role_id` bigint(20) NOT NULL COMMENT '角色id',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4;-- ----------------------------
-- Records of sys_user_role
-- ----------------------------
INSERT INTO `sys_user_role` VALUES ('1', '1', '1');
INSERT INTO `sys_user_role` VALUES ('2', '1', '2');
INSERT INTO `sys_user_role` VALUES ('3', '2', '2');

补上两张菜单表

-- ----------------------------
-- Table structure for sys_menu
-- ----------------------------
DROP TABLE IF EXISTS `sys_menu`;
CREATE TABLE `sys_menu` (`id` int(20) NOT NULL AUTO_INCREMENT,`parent_id` int(20) DEFAULT NULL COMMENT '父菜单ID,一级菜单为0',`name` varchar(64) NOT NULL COMMENT '菜单名称',`path` varchar(255) DEFAULT NULL COMMENT '菜单URL',`perms` varchar(255) DEFAULT NULL COMMENT '授权(多个用逗号分隔,如:user:list,user:create)',`component` varchar(255) DEFAULT NULL,`type` int(5) NOT NULL COMMENT '类型     0:目录   1:菜单   2:按钮',`icon` varchar(32) DEFAULT NULL COMMENT '菜单图标',`created_time` datetime NOT NULL COMMENT '菜单创建时间',`updated_time` datetime DEFAULT NULL COMMENT '菜单修改时间',`statu` int(5) NOT NULL COMMENT '状态1可用|0不可用',PRIMARY KEY (`id`),UNIQUE KEY `name` (`name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of sys_menu
-- ----------------------------
INSERT INTO `sys_menu` VALUES ('1', '0', '系统管理', '', 'sys:manage', '', '0', 'el-icon-s-operation', '2021-01-15 18:58:18', '2021-01-15 18:58:20', '1');INSERT INTO `sys_menu` VALUES ('2', '1', '用户管理', '/sys/users', 'sys:user:list', 'sys/User', '1', 'el-icon-s-custom', '2021-01-15 19:03:45', '2021-01-15 19:03:48', '1');INSERT INTO `sys_menu` VALUES ('3', '1', '角色管理', '/sys/roles', 'sys:role:list', 'sys/Role', '1', 'el-icon-rank', '2021-01-15 19:03:45', '2021-01-15 19:03:48', '1');INSERT INTO `sys_menu` VALUES ('4', '1', '菜单管理', '/sys/menus', 'sys:menu:list', 'sys/Menu', '1', 'el-icon-menu', '2021-01-15 19:03:45', '2021-01-15 19:03:48', '1');INSERT INTO `sys_menu` VALUES ('5', '0', '系统工具', '', 'sys:tools', null, '0', 'el-icon-s-tools', '2021-01-15 19:06:11', null, '1');INSERT INTO `sys_menu` VALUES ('6', '5', '数字字典', '/sys/dicts', 'sys:dict:list', 'sys/Dict', '1', 'el-icon-s-order', '2021-01-15 19:07:18', '2021-01-18 16:32:13', '1');INSERT INTO `sys_menu` VALUES ('7', '3', '添加角色', '', 'sys:role:save', '', '2', '', '2021-01-15 23:02:25', '2021-01-17 21:53:14', '0');INSERT INTO `sys_menu` VALUES ('8', '2', '添加用户', null, 'sys:user:save', null, '2', null, '2021-01-17 21:48:32', null, '1');-- ----------------------------
-- Table structure for sys_role_menu
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_menu`;
CREATE TABLE `sys_role_menu` (`id` int(20) NOT NULL AUTO_INCREMENT,`role_id` int(20) NOT NULL,`menu_id` int(20) NOT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=102 DEFAULT CHARSET=utf8mb4;-- ----------------------------
-- Records of sys_role_menu
-- ----------------------------
INSERT INTO `sys_role_menu` VALUES ('1', '1', '1');
INSERT INTO `sys_role_menu` VALUES ('2', '1', '2');
INSERT INTO `sys_role_menu` VALUES ('3', '1', '3');
INSERT INTO `sys_role_menu` VALUES ('4', '1', '4');
INSERT INTO `sys_role_menu` VALUES ('5', '1', '5');
INSERT INTO `sys_role_menu` VALUES ('6', '1', '6');
INSERT INTO `sys_role_menu` VALUES ('7', '1', '7');
INSERT INTO `sys_role_menu` VALUES ('8', '1', '8');
INSERT INTO `sys_role_menu` VALUES ('9', '2', '1');
INSERT INTO `sys_role_menu` VALUES ('10', '2', '2');
INSERT INTO `sys_role_menu` VALUES ('11', '2', '3');
INSERT INTO `sys_role_menu` VALUES ('12', '2', '4');
INSERT INTO `sys_role_menu` VALUES ('13', '2', '5');

使用mybatis-plus代码生成器

public class CodeGenerator {public static String scanner(String tip) {Scanner scanner = new Scanner(System.in);StringBuilder help = new StringBuilder();help.append("请输入" + tip + ":");System.out.println(help.toString());if (scanner.hasNext()) {String input= scanner.next();if (StringUtils.isNotEmpty(input)) {return input;}}throw new MybatisPlusException("请输入正确的" + tip + "!");}public static void main(String[] args) {// 代码生成器AutoGenerator mpg = new AutoGenerator();// 全局配置GlobalConfig gc = new GlobalConfig();String projectPath = System.getProperty("user.dir");gc.setOutputDir(projectPath + "/src/main/java");gc.setAuthor("Mr.jiang");gc.setOpen(false);gc.setServiceName("%sService");mpg.setGlobalConfig(gc);// 数据源配置DataSourceConfig dsc = new DataSourceConfig();dsc.setDbType(DbType.MYSQL);dsc.setUrl("jdbc:mysql://localhost:3306/securitytext?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai");dsc.setDriverName("com.mysql.cj.jdbc.Driver");dsc.setUsername("root");dsc.setPassword("1233");mpg.setDataSource(dsc);// 包配置PackageConfig pc = new PackageConfig();pc.setModuleName(null);pc.setParent("com.jsp");mpg.setPackageInfo(pc);// 策略配置StrategyConfig strategy = new StrategyConfig();strategy.setNaming(NamingStrategy.underline_to_camel);strategy.setColumnNaming(NamingStrategy.underline_to_camel);strategy.setEntityLombokModel(true);strategy.setRestControllerStyle(true);strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));strategy.setControllerMappingHyphenStyle(true);strategy.setTablePrefix("sys_");mpg.setStrategy(strategy);mpg.execute();}
}

创建mybatis-plus配置类

@Configuration
public class MybatisPlusConfig {// 分页配置@Beanpublic PaginationInterceptor paginationInterceptor() {PaginationInterceptor paginationInterceptor = new PaginationInterceptor();return paginationInterceptor;}
}
@Component
public class MyMetaObjectConfig implements MetaObjectHandler {// 自动插入、更新@Overridepublic void insertFill(MetaObject metaObject) {this.setFieldValByName("createTime", new Date(), metaObject);this.setFieldValByName("updateTime", new Date(), metaObject);}@Overridepublic void updateFill(MetaObject metaObject) {this.setFieldValByName("updateTime", new Date(), metaObject);}
}

这里是为了entiy类中的字段

      /*** 用户创建时间*/@TableField(fill = FieldFill.INSERT)@JsonFormat(pattern = "yyyy-MM-dd HH:mm", timezone = "GMT+8")private LocalDateTime createdTime;/*** 用户修改时间*/@TableField(fill = FieldFill.INSERT)@JsonFormat(pattern = "yyyy-MM-dd HH:mm", timezone = "GMT+8")private LocalDateTime updatedTime;/*** 用户上次登录时间*/@TableField(fill = FieldFill.INSERT_UPDATE)@JsonFormat(pattern = "yyyy-MM-dd HH:mm", timezone = "GMT+8")private LocalDateTime lastLoginTime;

Result结果集

@Data
public class Result implements Serializable {private int code;private String message;private Object data;Result(int code,String message,Object data) {this.code = code;this.message = message;this.data = data;}Result(int code,String message) {this.code = code;this.message = message;}
}
public enum ResultCode {//成功SUCCESS(200),//失败FAIL(400),//用户未认证UNAUTHORIZED(401),//url找不到NOT_FOUND(404),//访问受限FORBIDDEN(403),//服务器错误INTERNAL_SERVER_ERROR(500);public int code;ResultCode(int code) {this.code = code;}
}
public class ResultFactory {//成功public static Result successful(Object data) {return buildResult(ResultCode.SUCCESS, "成功", data);}//失败public static Result fail(String message) {return buildResult(ResultCode.FAIL, message, null);}public static Result buildResult(int ResultCode, String message, Object data) {return new Result(ResultCode, message, data);}public static Result buildResult(ResultCode ResultCode, String message, Object data) {return new Result(ResultCode.code, message, data);}public static Result buildResult(ResultCode ResultCode, String message) {return new Result(ResultCode.code, message);}}

** 重点 Spring Security 配置类

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate LoginFailureHandler loginFailureHandler;@Autowiredprivate LoginSuccessHandler loginSuccessHandler;@Autowiredprivate UserDetailsServiceImpl userDetailsService;@Autowiredprivate JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;@Autowiredprivate JwtAccessDeniedHandler jwtAccessDeniedHandler;@Autowiredprivate JwtLogoutSuccessHandler jwtLogoutSuccessHandler;@BeanJWTAuthenticationFilter jwtAuthenticationFilter() throws Exception {return new JWTAuthenticationFilter(authenticationManager());}@BeanBCryptPasswordEncoder bCryptPasswordEncoder() {return new BCryptPasswordEncoder();}//白名单public static final String[] URL_WHITELIST = {"/favicon.ico","/login","/logout",};@Overrideprotected void configure(HttpSecurity http) throws Exception {http.cors().and().csrf().disable()//关闭session.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().formLogin().successHandler(loginSuccessHandler).failureHandler(loginFailureHandler)//退出.and().logout().logoutSuccessHandler(jwtLogoutSuccessHandler)//资源访问控制.and().authorizeRequests()//白名单.antMatchers(URL_WHITELIST).permitAll()//其他请求需要认证.anyRequest().authenticated()//异常处理器.and().exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).accessDeniedHandler(jwtAccessDeniedHandler).and().addFilter(jwtAuthenticationFilter());}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService);}
}

重写UserDetails

public class MyUserDetails implements UserDetails {private Integer id;private String password;private final String username;private final Collection<? extends GrantedAuthority> authorities;private final boolean accountNonExpired;private final boolean accountNonLocked;private final boolean credentialsNonExpired;private final boolean enabled;public MyUserDetails(Integer id, String username, String password, Collection<? extends GrantedAuthority> authorities) {this(id, username, password, true, true, true, true, authorities);}public MyUserDetails(Integer id, String username, String password, boolean enabled, boolean accountNonExpired,boolean credentialsNonExpired, boolean accountNonLocked,Collection<? extends GrantedAuthority> authorities) {Assert.isTrue(username != null && !"".equals(username) && password != null,"Cannot pass null or empty values to constructor");this.id = id;this.username = username;this.password = password;this.enabled = enabled;this.accountNonExpired = accountNonExpired;this.credentialsNonExpired = credentialsNonExpired;this.accountNonLocked = accountNonLocked;this.authorities = authorities;}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return this.authorities;}@Overridepublic String getPassword() {return this.password;}@Overridepublic String getUsername() {return this.username;}@Overridepublic boolean isAccountNonExpired() {return this.accountNonExpired;}@Overridepublic boolean isAccountNonLocked() {return this.accountNonLocked;}@Overridepublic boolean isCredentialsNonExpired() {return this.credentialsNonExpired;}@Overridepublic boolean isEnabled() {return this.enabled;}
}

重写UserDetailsService

@Service
public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate UserMapper userMapper;@Autowiredprivate UserService userService;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//查询数据库判断username是否存在,如果不存在则抛出异常UsernameNotFoundExceptionQueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.eq("username", username);User user = userMapper.selectOne(wrapper);if (user == null) {throw new UsernameNotFoundException("用户名或密码不正确!");}//从数据库查出的用户信息id,username,password,authorityListList<GrantedAuthority> authorityList = getUserAuthority(user.getId());return new MyUserDetails(user.getId(), user.getUsername(), user.getPassword(), authorityList);}public List<GrantedAuthority> getUserAuthority(Integer id) {return AuthorityUtils.commaSeparatedStringToAuthorityList(userService.getUserAuthorityInfo(id));}
}
public interface UserRoleMapper extends BaseMapper<UserRole> {@Select("SELECT code, name FROM sys_user_role JOIN sys_role ON sys_user_role.role_id = sys_role.id WHERE user_id = #{uid};")List<Role> selectRoles(Integer uid);}
public interface UserMapper extends BaseMapper<User> {@Select("SELECT rm.menu_id FROM sys_user_role ur LEFT JOIN sys_role_menu rm ON ur.role_id = rm.role_id WHERE ur.user_id = #{uid};")List<Integer> getNavMenuIds(Integer uid);}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {@Autowiredprivate UserRoleMapper userRoleMapper;@Autowiredprivate UserMapper userMapper;//根据用户id获取用户角色@Overridepublic String getUserAuthorityInfo(Integer id) {List<Role> roles = userRoleMapper.selectRoles(id);List<Integer> menuIds = userMapper.getNavMenuIds(id);List<Menu> menus = menuMapper.selectBatchIds(menuIds);String roleNames = roles.stream().map(role -> "ROLE_" + role.getCode()).collect(Collectors.joining(","));String permNames  = menus.stream().map(menu -> menu.getPerms()).collect(Collectors.joining(","));//        ROLE_admin,ROLE_normal,sys:user:list...,String authority = roleNames.concat(",").concat(permNames);return authority;}@Overridepublic User getByUsername(String username) {QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.eq("username", username);User user = userMapper.selectOne(wrapper);return user;}
}

LoginSuccessHandler

@Component
public class LoginSuccessHandler implements AuthenticationSuccessHandler {@Autowiredprivate JwtUtil jwtUtil;@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {response.setContentType("application/json;charset=UTF-8");ServletOutputStream outputStream = response.getOutputStream();// 生成jwt返回String token = jwtUtil.generateToken(authentication.getName());response.setHeader(jwtUtil.getHeader(), token);Result result = ResultFactory.successful("");outputStream.write(JSONUtil.toJsonStr(result).getBytes("UTF-8"));outputStream.flush();outputStream.close();}
}

LoginFailureHandler

@Component
public class LoginFailureHandler implements AuthenticationFailureHandler {@Overridepublic void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {response.setContentType("application/json;charset=UTF-8");ServletOutputStream outputStream = response.getOutputStream();Result result = ResultFactory.fail("Bad credentials".equals(exception.getMessage()) ? "用户名或密码不正确" : exception.getMessage());outputStream.write(JSONUtil.toJsonStr(result).getBytes("UTF-8"));outputStream.flush();outputStream.close();}
}

JwtLogoutSuccessHandler

@Component
public class JwtLogoutSuccessHandler implements LogoutSuccessHandler {@Autowiredprivate JwtUtil jwtUtil;@Overridepublic void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {if (authentication != null) {new SecurityContextLogoutHandler().logout(request, response, authentication);}response.setContentType("application/json;charset=UTF-8");ServletOutputStream outputStream = response.getOutputStream();response.setHeader(jwtUtil.getHeader(), "");Result result = ResultFactory.successful("");outputStream.write(JSONUtil.toJsonStr(result).getBytes("UTF-8"));outputStream.flush();outputStream.close();}
}

JwtAuthenticationEntryPoint

@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {@Overridepublic void commence(HttpServletRequest httpServletRequest, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {response.setContentType("application/json;charset=UTF-8");response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);ServletOutputStream outputStream = response.getOutputStream();Result result = ResultFactory.buildResult(ResultCode.UNAUTHORIZED, "请先登录!");outputStream.write(JSONUtil.toJsonStr(result).getBytes("UTF-8"));outputStream.flush();outputStream.close();}
}

JwtAccessDeniedHandler

@Component
public class JwtAccessDeniedHandler implements AccessDeniedHandler {@Overridepublic void handle(HttpServletRequest httpServletRequest, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {response.setContentType("application/json;charset=UTF-8");response.setStatus(HttpServletResponse.SC_FORBIDDEN);ServletOutputStream outputStream = response.getOutputStream();//Result result = ResultFactory.fail(e.getMessage());Result result = ResultFactory.buildResult(ResultCode.FORBIDDEN,"权限不足");outputStream.write(JSONUtil.toJsonStr(result).getBytes("UTF-8"));outputStream.flush();outputStream.close();}
}

jwt相关配置

JwtUtil

@Data
@Component
@ConfigurationProperties(prefix = "xiaojiang.jwt")
public class JwtUtil {private long expire;private String secret;private String header;//生成JWTpublic String generateToken(String username) {Date exireDate = new Date(new Date().getTime() + 1000 * expire);return Jwts.builder().setHeaderParam("typ", "JWT").setSubject(username).setIssuedAt(new Date()).setExpiration(exireDate).signWith(SignatureAlgorithm.HS256, secret).compact();}//解析JWTpublic Claims getClaimByToken(String jwt) {try {return Jwts.parser().setSigningKey(secret).parseClaimsJws(jwt).getBody();} catch (Exception e) {return null;}}//JWT是否过期public boolean isTokenExpired(Claims claims) {return claims.getExpiration().before(new Date());}
}

JWTAuthenticationFilter

public class JWTAuthenticationFilter extends BasicAuthenticationFilter {@Autowiredprivate UserService userService;@Autowiredprivate JwtUtil jwtUtil;@Autowiredprivate UserDetailsServiceImpl userDetailsService;public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {super(authenticationManager);}protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {String jwt = request.getHeader(jwtUtil.getHeader());if (StrUtil.isBlankOrUndefined(jwt)) {chain.doFilter(request, response);return;}Claims claim = jwtUtil.getClaimByToken(jwt);if (claim == null) {throw new JwtException("token异常");}if (jwtUtil.isTokenExpired(claim)) {throw new JwtException("token已过期");}String username = claim.getSubject();//获取用户的权限等信息User user = userService.getByUsername(username);List<GrantedAuthority> userAuthority = userDetailsService.getUserAuthority(user.getId());UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, null, userAuthority);System.out.println("token->" + token);SecurityContextHolder.getContext().setAuthentication(token);chain.doFilter(request, response);}}

ok大功告成 使用postman试试效果

admin用户拥有admin和normal角色,test用户拥有normal角色

在Controller中分配接口权限

//  如果使用 @PreAuthorize("hasRole('ROLE_ADMIN')")需要在类的头部加上@EnableGlobalMethodSecurity(prePostEnabled = true) //打开权限验证@RestController
@RequestMapping("/user")
@EnableGlobalMethodSecurity(prePostEnabled = true)  //打开权限验证
public class UserController {@Autowiredprivate UserService userService;@PreAuthorize("hasRole('admin')")@GetMapping("/admin")public String hello() {return "hello admin";}@PreAuthorize("hasRole('normal')")@GetMapping("/test")public String test() {return "hello test";}@PreAuthorize("hasRole('admin')")@GetMapping("/list")public Result list() {return ResultFactory.successful(userService.list());}}

首先使用admin用户登录

在Header中有Authorization,也就是我们需要的token


接着使用admin用户的token去访问其他接口

admin用户都可以访问

接着使用test用户登录



使用test用户去访问其他接口

因为test用户只有normal角色,所以只能访问test接口,admin接口权限不足

还待完善!!!

Spring boot 整合Spring Security Jwt相关推荐

  1. spring boot整合spring security笔记

    最近自己做了一个小项目,正在进行springboot和spring Security的整合,有一丢丢的感悟,在这里分享一下: 首先,spring boot整合spring security最好是使用T ...

  2. 认证与授权流程与spring boot整合 spring security(1)

    一   spring security 1.1 spring security的作用 Spring Security所解决的问题就是安全访问控制,而安全访问控制功能其实就是对所有进入系统的请求进行拦截 ...

  3. springboot整合hibernate_峰哥说技术系列-17 .Spring Boot 整合 Spring Data JPA

    今日份主题 Spring Boot 整合 Spring Data JPA JPA(Java Persistence API)是用于对象持久化的 API,是Java EE 5.0 平台标准的 ORM 规 ...

  4. Spring Boot 整合——Spring batch重试和回滚

    关于版本 依赖 版本 springboot 2.4.0 spring batch 2.4.0 代码地址 因为每个例子涉及代码较多,且包含测试用例,如果都贴到文章中内容过多,所以只贴出了部分代码.全部的 ...

  5. 二、何为Spring Boot整合Spring Cloud?

    题语:学习方法之多思考:正向.逆向.跳跃 作者:A哥(YourBatman) wx号:fsx641385712(备注"Java群"字样) 公众号:BAT的乌托邦(ID:BAT-ut ...

  6. spring boot 整合 spring cache 简单使用

    spring boot 整合 spring cache 简单使用 spring cache简介 使用spring cache spring cache简介 Spring 3.1起,提供了基于注解的对C ...

  7. Spring Boot 整合——Spring Boot整合kafka整合

    Spring Boot 整合之前的内容 项目名称 描述 地址 base-data-mybatis 整合mybatis-plus(实际上官方教程已经很多,只做了自定义插件) 未完成 base-jpa J ...

  8. Spring Boot 整合 Spring Security 示例

    点击关注公众号,Java干货及时送达 一.说明 SpringSecurity是一个用于Java 企业级应用程序的安全框架,主要包含用户认证和用户授权两个方面.相比较Shiro而言,Security功能 ...

  9. Spring Boot整合Spring Data JPA操作数据

    一. Sping Data JPA 简介 Spring Data JPA 是 Spring 基于 ORM 框架.JPA 规范的基础上封装的一套 JPA 应用框架,底层使用了 Hibernate 的 J ...

最新文章

  1. C++知识点53——虚继承
  2. 优化 UI 应用启动时间的方法
  3. 服务器 风扇测试软件,图解服务器风扇安装的正确方法
  4. asterisk1.8 Makefile分析 (1)
  5. html之属性的应用
  6. 【OpenCV 例程200篇】51. 图像增强—直方图反向追踪
  7. Python 创建随机mac地址(单播、组播)
  8. kubernetes英语怎么读_小学三年级英语怎么学
  9. 刘乾四川大学计算机学院刘乾,计算机学院2011~2012学年-四川大学计算机学院.doc...
  10. 电脑快捷方式变白原因及解决方法——血的教训呜呜呜
  11. exagear安装java_exagear模拟器怎么使用 exagear模拟器使用方法安装教程
  12. debian设置IP
  13. 金蝶云星空html5的网页主界面如何修改,金蝶云星空启用科目管控后,科目相关的值更新事件无法生效原因及解决办法...
  14. 献计《权力的游戏》珊莎•斯塔克
  15. python快速幂算法解决大数取模
  16. Scratch编程初体验-小猫跳舞
  17. 【安卓wechat微信导出聊天记录】
  18. excel汇总怎么做?
  19. 关于MAX232芯片总是发热的问题
  20. vm15安装mac 未能与服务器联系,VMware15/16解锁VMware安装MacOS的步骤详解

热门文章

  1. node-sass是什么?
  2. 首届“发现杯”软件设计大奖赛启动
  3. (阿里云)Linux部署SSM项目全过程
  4. 高性能服务器设计[转自腾讯km,由qzhang同学翻译]
  5. stm32心率监测系统(心率监测,wifi上传,APP显示,上位机显示)
  6. 解决谷歌的but your computer or network may be sending automated queries
  7. nuc企业微信自动打卡 autojs
  8. 日文配列键盘修改和映射自定义
  9. Latex中一些特殊常用符号的输入
  10. 谷粒商城基础篇——Day01