SpringBoot集成Spring security JWT實現(xiàn)接口權(quán)限認(rèn)證
1、添加依賴
<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>
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;// 令牌環(huán)有效期 public static final String SECRET="abc123456def";//令牌環(huán)密鑰 public static final String TOKEN_PREFIX="Bearer";//令牌環(huán)頭標(biāo)識 public static final String HEADER_STRING="Passport";//配置令牌環(huán)在http heads中的鍵值 public static final String ROLE="ROLE";//自定義字段-角色字段 //生成令牌環(huán) public static String generateToken(String userRole,String userid){ HashMap<String,Object> 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; } //生成令牌環(huán) public static String generateToken(String userRole,String userid,long exprationtime){ HashMap<String,Object> 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; } //令牌環(huán)校驗 public static Map<String,Object> validateTokenAndGetClaims(HttpServletRequest request){ String token=request.getHeader(HEADER_STRING); if(token==null){ throw new TokenValidationException("Missing Token"); } else{ Map<String,Object> 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/**"}; //哪 些請求需要進(jìn)行安全校驗 public JwtAuthenticationFilter() { } @Override protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { //是不是可以在這里做多種方式登錄呢 try { if (isProtectedUrl(httpServletRequest)) { Map<String, Object> claims = JwtUtils.validateTokenAndGetClaims(httpServletRequest); String role = String.valueOf(claims.get(ROLE)); String userid = String.valueOf(claims.get("userid")); //最關(guān)鍵的部分就是這里, 我們直接注入了 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); } //是否是保護(hù)連接 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類(配置類)
跨域訪問:客戶端與服務(wù)端域名不同或是端口號不同。防止跨域攻擊
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需要進(jìn)行校驗--所有請求都需要校驗"/" .antMatchers("/public/**").permitAll() //那些請求不需要校驗 .anyRequest().authenticated() //自定義校驗類 .and() .addFilterBefore(new JwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class) .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS)//關(guān)閉session ; } }
5、Action注解
在Controller類中添加
@CrossOrigin @RestController @PreAuthorize("hasAuthority('admin')") //配置角色,擁有該角色的用戶方可訪問 @RequestMapping("/manage")
postman測試http://localhost:7070/manage/userList,不可訪問
public開頭的可以訪問
6、token令牌環(huán),訪問需校驗的資源
public的Controller類添加
@PostMapping("/login") @ResponseBody public HashMap<String,String> 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<String,String>(){{ put("msg","ok"); put("token",jwt); // put("role",u.getRoleid()); put("role","admin"); }}; } else { //return new ResponseEntity(HttpStatus.UNAUTHORIZED); return new HashMap<String,String>(){{ put("msg","error"); put("token","error"); }}; } } public static class Account{ public String username; public String password; }
postman測試,隨便輸用戶名密碼
輸入代碼中的用戶名密碼
去JWT官網(wǎng)https://jwt.io/,頁面下滑,將得到的token輸入,得到
manage的Controller類中添加測試
@GetMapping("testSecurityResource") @ResponseBody public String testSecurityResource() throws Exception{ return "受保護(hù)的資源"; }
用postman訪問http://localhost:7070/manage/testSecurityResource,返回結(jié)果
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 */ @Controller public 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();//從令牌環(huán)中獲取userid String getCurrentRole();//從令牌環(huán)中獲取角色id
ServiceImpl
/** * 獲取當(dāng)前登錄用的的Id * @return */ @Override public String getCurrentUserId() { String userid= (String) SecurityContextHolder.getContext().getAuthentication() .getPrincipal(); if(CommonController.isNullOrSpace(userid)){ return null; } else { return userid; } } /** * 獲取當(dāng)前登錄用戶的角色 * @return */ @Override public String getCurrentRole() { String role=null; Collection<SimpleGrantedAuthority> authorities = (Collection<SimpleGrantedAuthority>) 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 "受保護(hù)的資源,當(dāng)前用戶的id是"+userid+"當(dāng)前用戶的角色是"+role; }
用postman測試
這是前面自定義的
8、識別token信息
如果將下圖中的角色換掉,將不能訪問
9、自動更新令牌環(huán)
添加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; /** * 令牌環(huán)自動更新 * @Author HeYunHui * @create 2020/11/16 17:24 * @PreAuthorize("hasAuthority('admin')")//只允許有admin角色的用戶訪問 hasAnyAuthority([auth1,auth2]) */ @CrossOrigin @RestController @PreAuthorize("hasAnyAuthority('admin','member')") @RequestMapping("/auth") public class AuthController { /** * 更新令牌環(huán)信息 * @param request * @return */ @GetMapping("refreshToken") @ResponseBody public HashMap<String,String> refreshToken(HttpServletRequest request){ String role=null; Collection<SimpleGrantedAuthority> authorities = (Collection<SimpleGrantedAuthority>) 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<String,String>(){{ put("token","error"); }}; } else{ String jwt=""; //一小時 jwt= JwtUtils.generateToken(role,userid,60*60*1000); HashMap<String,String> m=new HashMap<>(); m.put("token",jwt); return m; } } /** * 獲取當(dāng)前登錄用戶的角色 * @return */ @GetMapping("getRole") @ResponseBody public HashMap<String,String> getRoleByToken(){ String role=""; String userid=""; Collection<SimpleGrantedAuthority> authorities = (Collection<SimpleGrantedAuthority>) SecurityContextHolder.getContext().getAuthentication().getAuthorities(); for (GrantedAuthority authority : authorities) { role = authority.getAuthority(); } if(CommonController.isNullOrSpace(role)){ return new HashMap<String,String>(){{ put("role","error"); }}; } else{ HashMap<String,String> m=new HashMap<>(); m.put("role",role); return m; } } }
用postman測試
10、使用數(shù)據(jù)庫存儲用戶信息
(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 @Mapper public interface UserMapper extends BaseMapper<Users> { List<Users> getUsersByUsrNameAndPwd(@Param("usrName")String usrName, @Param("usrPwd") String usrPwd); }
UsersMapper.xml
<?xml version="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.dreamteam.chdapp.mapper.UserMapper"> <select id="getUsersByUsrNameAndPwd" resultType="com.dreamteam.chdapp.entity.Users"> select * from users where #{usrName}=usr_name and #{usrPwd}=usr_pwd </select> </mapper>
service
Users getUsersByUsrNameAndPwd(String usrName,String usrPwd);
serviceImpl JWT獲取用戶名密碼
@Override public Users getUsersByUsrNameAndPwd(String usrName, String usrPwd) { List<Users> ul=userMapper.getUsersByUsrNameAndPwd(usrName,usrPwd); if(ul.size()>0){ return ul.get(0); } return null; }
Controller
@PostMapping("/login") @ResponseBody public HashMap<String,String> 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<String,String>(){{ put("msg","ok"); put("token",jwt); put("role",u.getUsrType()); // put("role","admin"); }}; } else { //return new ResponseEntity(HttpStatus.UNAUTHORIZED); return new HashMap<String,String>(){{ put("msg","error"); put("token","error"); }}; } } public static class Account{ public String username; public String password; }
postman測試
a.登錄,生成token
b.輸入token訪問manage下的鏈接
到此這篇關(guān)于SpringBoot集成Spring security JWT實現(xiàn)接口權(quán)限認(rèn)證的文章就介紹到這了,更多相關(guān)SpringBoot 接口權(quán)限認(rèn)證內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺析java程序中hibernate的應(yīng)用總結(jié)
hibernate可以理解為是一個中間件它負(fù)責(zé)把java程序的sql語句接收過來發(fā)送到數(shù)據(jù)庫,而數(shù)據(jù)庫返回來的信息hibernate接收之后直接生成一個對象傳給java2013-07-07基于IDEA創(chuàng)建SpringMVC項目流程圖解
這篇文章主要介紹了基于IDEA創(chuàng)建SpringMVC項目流程圖解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-10-10Spring boot連接MySQL 8.0可能出現(xiàn)的問題
這篇文章主要給大家介紹了關(guān)于Spring boot連接MySQL 8.0可能出現(xiàn)的問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-10-10