软件编程
位置:首页>> 软件编程>> java编程>> SpringBoot集成Spring security JWT实现接口权限认证

SpringBoot集成Spring security JWT实现接口权限认证

作者:雨云21  发布时间:2023-02-02 07:31:08 

标签:SpringBoot,接口,权限认证

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;// 令牌环有效期
   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<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;
   }
   //生成令牌环
   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;
   }

//令牌环校验
   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/**"}; //哪  些请求需要进行安全校验

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"));
               //最关键的部分就是这里, 我们直接注入了
               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,不可访问

SpringBoot集成Spring security JWT实现接口权限认证

public开头的可以访问

6、token令牌环,访问需校验的资源

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测试,随便输用户名密码

SpringBoot集成Spring security JWT实现接口权限认证

输入代码中的用户名密码

SpringBoot集成Spring security JWT实现接口权限认证

去JWT官网https://jwt.io/,页面下滑,将得到的token输入,得到

SpringBoot集成Spring security JWT实现接口权限认证

manage的Controller类中添加测试


   @GetMapping("testSecurityResource")
   @ResponseBody
   public String testSecurityResource() throws Exception{

return "受保护的资源";
   }

用postman访问http://localhost:7070/manage/testSecurityResource,返回结果

SpringBoot集成Spring security JWT实现接口权限认证

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();//从令牌环中获取userid
String 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<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 "受保护的资源,当前用户的id是"+userid+"当前用户的角色是"+role;

}

用postman测试

SpringBoot集成Spring security JWT实现接口权限认证

这是前面自定义的

SpringBoot集成Spring security JWT实现接口权限认证

8、识别token信息

SpringBoot集成Spring security JWT实现接口权限认证

如果将下图中的角色换掉,将不能访问

SpringBoot集成Spring security JWT实现接口权限认证

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([auth1,auth2])
*/
@CrossOrigin
@RestController
@PreAuthorize("hasAnyAuthority('admin','member')")
@RequestMapping("/auth")
public class AuthController {
   /**
    * 更新令牌环信息
    * @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;

}

}

/**
    * 获取当前登录用户的角色
    * @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测试

SpringBoot集成Spring security JWT实现接口权限认证

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
@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

SpringBoot集成Spring security JWT实现接口权限认证

b.输入token访问manage下的链接

SpringBoot集成Spring security JWT实现接口权限认证

来源:https://blog.csdn.net/hyh17808770899/article/details/109733851

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com