Springboot中怎么集成Spring Security JWT实现接口权限认证
发表于:2025-01-16 作者:千家信息网编辑
千家信息网最后更新 2025年01月16日,小编给大家分享一下Springboot中怎么集成Spring Security JWT实现接口权限认证,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下
千家信息网最后更新 2025年01月16日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安全错误
数据库的锁怎样保障安全
如何设置sql数据库
国家哲学社会科数据库
供电所网络安全培训心得
云亚网络安全吗
数字化转型与软件开发
云服务器上部署k8s的硬件要求
嘉定区新能源软件开发模板规格
南昌市网络安全态势
与网络安全有关股票
数据库完整性与安全性区别与联系
奥的斯服务器上下减速开关
数据库表格第一列无法输入
me软件开发公司
iptv管理服务器
华为手机的软件开发商
服务器无尘机房
oracle整个数据库迁移
更大的数据库
电信的代理服务器
河南2020网络安全启动仪式
以下关于数据库模式描述错误的是
网络技术与应用期末考试
阿里数据库监听
电商平台数据库需要哪些技术
哈理工数据库大作业
服务器属于什么税务编码
阿里云登陆服务器
深圳的软件开发一般什么工资
读取dat文件中的列数据库
凌云诺不同服务器能一起玩吗