Springboot中怎么集成Spring Security JWT实现接口权限认证
发表于:2025-02-23 作者:千家信息网编辑
千家信息网最后更新 2025年02月23日,小编给大家分享一下Springboot中怎么集成Spring Security JWT实现接口权限认证,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下
千家信息网最后更新 2025年02月23日Springboot中怎么集成Spring Security JWT实现接口权限认证
小编给大家分享一下Springboot中怎么集成Spring Security JWT实现接口权限认证,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!
1、添加依赖
org.springframework.boot spring-boot-starter-security io.jsonwebtoken jjwt 0.9.1
2、集成JWT工具类(JwtUtils)
package com.dreamteam.chdapp.utils;import io.jsonwebtoken.Jwts;import io.jsonwebtoken.SignatureAlgorithm;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import javax.servlet.http.HttpServletRequest;import java.util.Date;import java.util.HashMap;import java.util.Map;/** * @Author HeYunHui * @create 2020/11/15 14:12 */public class JwtUtils { private static final Logger logger= LoggerFactory.getLogger(JwtUtils.class); public static final long EXPIRATION_TIME=60*60*1000;// 令牌环有效期 public static final String SECRET="abc123456def";//令牌环密钥 public static final String TOKEN_PREFIX="Bearer";//令牌环头标识 public static final String HEADER_STRING="Passport";//配置令牌环在http heads中的键值 public static final String ROLE="ROLE";//自定义字段-角色字段 //生成令牌环 public static String generateToken(String userRole,String userid){ HashMap map=new HashMap<>(); map.put(ROLE,userRole); map.put("userid",userid); String jwt= Jwts.builder() .setClaims(map) .setExpiration(new Date(System.currentTimeMillis()+EXPIRATION_TIME)) .signWith(SignatureAlgorithm.HS512,SECRET) .compact(); return TOKEN_PREFIX+" "+jwt; } //生成令牌环 public static String generateToken(String userRole,String userid,long exprationtime){ HashMap map=new HashMap<>(); map.put(ROLE,userRole); map.put("userid",userid); String jwt= Jwts.builder() .setClaims(map) .setExpiration(new Date(System.currentTimeMillis()+exprationtime)) .signWith(SignatureAlgorithm.HS512,SECRET) .compact(); return TOKEN_PREFIX+" "+jwt; } //令牌环校验 public static Map validateTokenAndGetClaims(HttpServletRequest request){ String token=request.getHeader(HEADER_STRING); if(token==null){ throw new TokenValidationException("Missing Token"); } else{ Map body= Jwts.parser() .setSigningKey(SECRET) .parseClaimsJws(token.replace(TOKEN_PREFIX,"")) .getBody(); return body; } } static class TokenValidationException extends RuntimeException{ public TokenValidationException(String msg){ super(msg); } }}
3、集成JWT filter(拦截器/过滤器)
package com.dreamteam.chdapp.filter;import com.dreamteam.chdapp.utils.JwtUtils;import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;import org.springframework.security.core.context.SecurityContextHolder;import org.springframework.util.AntPathMatcher;import org.springframework.util.PathMatcher;import org.springframework.web.filter.OncePerRequestFilter;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.Arrays;import java.util.Map;import static com.dreamteam.chdapp.utils.JwtUtils.ROLE;/** * @Author HeYunHui * @create 2020/11/15 14:46 */public class JwtAuthenticationFilter extends OncePerRequestFilter { private static final PathMatcher pathmatcher = new AntPathMatcher(); private String[] protectUrlPattern = {"/manage/**", "/member/**", "/auth/**"}; //哪 些请求需要进行安全校验 public JwtAuthenticationFilter() { } @Override protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {//是不是可以在这里做多种方式登录呢 try { if (isProtectedUrl(httpServletRequest)) { Map claims = JwtUtils.validateTokenAndGetClaims(httpServletRequest); String role = String.valueOf(claims.get(ROLE)); String userid = String.valueOf(claims.get("userid")); //最关键的部分就是这里, 我们直接注入了 SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken( userid, null, Arrays.asList(() -> role) )); } } catch (Exception e) { e.printStackTrace(); httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage()); return; } filterChain.doFilter(httpServletRequest, httpServletResponse); } //是否是保护连接 private boolean isProtectedUrl(HttpServletRequest request) { boolean flag = false; for (int i = 0; i < protectUrlPattern.length; i++) { if (pathmatcher.match(protectUrlPattern[i], request.getServletPath())) { return true; } } return false; }}
4、配置JWT config类(配置类)
跨域访问:客户端与服务端域名不同或是端口号不同。防止跨域攻击
package edu.ynmd.cms.config;import edu.ynmd.cms.filter.JwtAuthenticationFilter;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;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.annotation.web.configuration.WebSecurityConfigurerAdapter;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.authentication.UsernamePasswordAuthenticationFilter;import org.springframework.security.web.firewall.HttpFirewall;import org.springframework.security.web.firewall.StrictHttpFirewall;@Configuration@EnableWebSecurity@EnableGlobalMethodSecurity(prePostEnabled = true)public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } @Bean public HttpFirewall allowUrlEncodedSlashHttpFirewall() { StrictHttpFirewall firewall = new StrictHttpFirewall(); firewall.setAllowUrlEncodedSlash(true); return firewall; } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .cors() //允许跨域访问 .and() .authorizeRequests() .antMatchers("/").authenticated() //配置那些url需要进行校验--所有请求都需要校验"/" .antMatchers("/public/**").permitAll() //那些请求不需要校验 .anyRequest().authenticated() //自定义校验类 .and() .addFilterBefore(new JwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class) .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS)//关闭session ; }}
5、Action注解
在Controller类中添加
@CrossOrigin@RestController@PreAuthorize("hasAuthority('admin')") //配置角色,拥有该角色的用户方可访问@RequestMapping("/manage")
postman测试http://localhost:7070/manage/userList,不可访问
public开头的可以访问
6、token令牌环,访问需校验的资源
public的Controller类添加
@PostMapping("/login") @ResponseBody public HashMap login( @RequestBody Account account) throws IOException {// Users u=manageService.getUserByUserNameAndPass(account.username,account.password); if(account.username.equals("admin")&&account.password.equals("123456")){// if(u!=null){ String jwt= JwtUtils.generateToken("admin","123456789abc");// String jwt= JwtUtils.generateToken(u.getRoleid(),u.getUsersid()); return new HashMap(){{ put("msg","ok"); put("token",jwt);// put("role",u.getRoleid()); put("role","admin"); }}; } else { //return new ResponseEntity(HttpStatus.UNAUTHORIZED); return new HashMap(){{ put("msg","error"); put("token","error"); }}; } } public static class Account{ public String username; public String password; }
postman测试,随便输用户名密码
输入代码中的用户名密码
去JWT官网https://jwt.io/,页面下滑,将得到的token输入,得到
manage的Controller类中添加测试
@GetMapping("testSecurityResource") @ResponseBody public String testSecurityResource() throws Exception{ return "受保护的资源"; }
用postman访问http://localhost:7070/manage/testSecurityResource,返回结果
7、service工具类
通用请求处理
package com.dreamteam.chdapp.controller.common;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Controller;/** * 通用请求处理 * @Author HeYunHui * @create 2020/11/14 15:38 */@Controllerpublic class CommonController { protected static final Logger log= LoggerFactory.getLogger(CommonController.class); /** * 字符串为空 * @param value * @return */ public static boolean isNullOrSpace(String value){ if(value==null){ return true; } else { if(value.equals("")){ return true; } else { return false; } } }}
Service层
String getCurrentUserId();//从令牌环中获取useridString getCurrentRole();//从令牌环中获取角色id
ServiceImpl
/** * 获取当前登录用的的Id * @return */ @Override public String getCurrentUserId() { String userid= (String) SecurityContextHolder.getContext().getAuthentication() .getPrincipal(); if(CommonController.isNullOrSpace(userid)){ return null; } else { return userid; } } /** * 获取当前登录用户的角色 * @return */ @Override public String getCurrentRole() { String role=null; Collection authorities = (Collection) SecurityContextHolder.getContext().getAuthentication().getAuthorities(); for (GrantedAuthority authority : authorities) { role = authority.getAuthority(); } if(CommonController.isNullOrSpace(role)){ return null; } else{ return role; } }
修改manage的Controller类
@GetMapping("testSecurityResource") @ResponseBody public String testSecurityResource() throws Exception{ String userid=userInfoService.getCurrentUserId(); String role=userInfoService.getCurrentRole(); return "受保护的资源,当前用户的id是"+userid+"当前用户的角色是"+role; }
用postman测试
这是前面自定义的
8、识别token信息
如果将下图中的角色换掉,将不能访问
9、自动更新令牌环
添加Controller类
package com.dreamteam.chdapp.controller;import com.dreamteam.chdapp.controller.common.CommonController;import com.dreamteam.chdapp.utils.JwtUtils;import org.springframework.security.access.prepost.PreAuthorize;import org.springframework.security.core.GrantedAuthority;import org.springframework.security.core.authority.SimpleGrantedAuthority;import org.springframework.security.core.context.SecurityContextHolder;import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletRequest;import java.util.Collection;import java.util.HashMap;/** * 令牌环自动更新 * @Author HeYunHui * @create 2020/11/16 17:24 * @PreAuthorize("hasAuthority('admin')")//只允许有admin角色的用户访问 hasAnyAuthority([auth2,auth3]) */@CrossOrigin@RestController@PreAuthorize("hasAnyAuthority('admin','member')")@RequestMapping("/auth")public class AuthController { /** * 更新令牌环信息 * @param request * @return */ @GetMapping("refreshToken") @ResponseBody public HashMap refreshToken(HttpServletRequest request){ String role=null; Collection authorities = (Collection) SecurityContextHolder.getContext().getAuthentication().getAuthorities(); for (GrantedAuthority authority : authorities) { role = authority.getAuthority(); } // UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication() .getPrincipal(); String userid= (String)SecurityContextHolder.getContext().getAuthentication() .getPrincipal(); if(CommonController.isNullOrSpace(role)){ return new HashMap(){{ put("token","error"); }}; } else{ String jwt=""; //一小时 jwt= JwtUtils.generateToken(role,userid,60*60*1000); HashMap m=new HashMap<>(); m.put("token",jwt); return m; } } /** * 获取当前登录用户的角色 * @return */ @GetMapping("getRole") @ResponseBody public HashMap getRoleByToken(){ String role=""; String userid=""; Collection authorities = (Collection) SecurityContextHolder.getContext().getAuthentication().getAuthorities(); for (GrantedAuthority authority : authorities) { role = authority.getAuthority(); } if(CommonController.isNullOrSpace(role)){ return new HashMap(){{ put("role","error"); }}; } else{ HashMap m=new HashMap<>(); m.put("role",role); return m; } }}
用postman测试
10、使用数据库存储用户信息
(1)实体类
package com.dreamteam.chdapp.entity;import com.baomidou.mybatisplus.annotation.IdType;import com.baomidou.mybatisplus.annotation.TableId;import com.baomidou.mybatisplus.annotation.TableName;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import org.springframework.stereotype.Component;@Component@Data@AllArgsConstructor@NoArgsConstructor/** * 表名 */@TableName("users")public class Users { @TableId(type = IdType.AUTO) private String usrId; private String usrName; private String usrTel; private String usrPwd; private String usrType; }
UserMapper
package com.dreamteam.chdapp.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;import com.dreamteam.chdapp.entity.Users;import org.apache.ibatis.annotations.Mapper;import org.apache.ibatis.annotations.Param;import org.springframework.stereotype.Repository;import java.util.List;/** * @Author HeYunHui * @create 2020/11/11 21:50 */@Repository@Mapperpublic interface UserMapper extends BaseMapper { List getUsersByUsrNameAndPwd(@Param("usrName")String usrName, @Param("usrPwd") String usrPwd);}
UsersMapper.xml
service
Users getUsersByUsrNameAndPwd(String usrName,String usrPwd);
serviceImpl JWT获取用户名密码
@Override public Users getUsersByUsrNameAndPwd(String usrName, String usrPwd) { List ul=userMapper.getUsersByUsrNameAndPwd(usrName,usrPwd); if(ul.size()>0){ return ul.get(0); } return null; }
Controller
@PostMapping("/login") @ResponseBody public HashMap login( @RequestBody Account account) throws IOException { Users u=userInfoService.getUsersByUsrNameAndPwd(account.username,account.password);// if(account.username.equals("admin")&&account.password.equals("123456")){ if(u!=null){// String jwt= JwtUtils.generateToken("admin","123456789abc"); String jwt= JwtUtils.generateToken(u.getUsrType(),u.getUsrId()); return new HashMap(){{ put("msg","ok"); put("token",jwt); put("role",u.getUsrType());// put("role","admin"); }}; } else { //return new ResponseEntity(HttpStatus.UNAUTHORIZED); return new HashMap(){{ put("msg","error"); put("token","error"); }}; } } public static class Account{ public String username; public String password; }
以上是"Springboot中怎么集成Spring Security JWT实现接口权限认证"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!
令牌
用户
角色
测试
配置
登录
信息
密码
用户名
篇文章
资源
保护
更新
接口
权限
认证
不同
内容
字段
工具
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
兖矿休闲网络安全知识
代理服务器排名
全省教育系统网络安全
电商数据库描述
河南放心软件开发设施有哪些
学网络技术一年多少钱
网络安全保险如何定价
网络安全知识应急应会
linux邮件服务器
护苗网络安全课程体会
软件开发工作量评测
中华人民共和国网络安全规定
数据库原理多少页
汽车嵌入式软件开发标准
国产服务器机柜报价
网络技术服务公司营业税率
杭州小溪网络技术
台州手机棋牌软件开发公司
生鲜配送软件开发平台
java软件开发是干什么
面向对象是一种软件开发方法
java软件开发培训哪家好
数据库表对应关系
网络技术改变生活的案例
web服务器的安全方案
大兴机房服务器回收新报价
护苗网络安全课程体会
韶关喵咪网络技术有限公司
软件开发怎么自学程的软件
服务器售后服务方案