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

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,不可访问

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

输入代码中的用户名密码

去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
 */
@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测试

这是前面自定义的

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([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测试

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

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

到此这篇关于SpringBoot集成Spring security JWT实现接口权限认证的文章就介绍到这了,更多相关SpringBoot 接口权限认证内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • SpringBoot和Redis实现Token权限认证的实例讲解

    一.引言 登陆权限控制是每个系统都应必备的功能,实现方法也有好多种.下面使用Token认证来实现系统的权限访问. 功能描述: 用户登录成功后,后台返回一个token给调用者,同时自定义一个@AuthToken注解,被该注解标注的API请求都需要进行token效验,效验通过才可以正常访问,实现接口级的鉴权控制. 同时token具有生命周期,在用户持续一段时间不进行操作的话,token则会过期,用户一直操作的话,则不会过期. 二.环境 SpringBoot Redis(Docke中镜像) MySQL

  • springboot+jwt实现token登陆权限认证的实现

    一 前言 此篇文章的内容也是学习不久,终于到周末有时间码一篇文章分享知识追寻者的粉丝们,学完本篇文章,读者将对token类的登陆认证流程有个全面的了解,可以动态搭建自己的登陆认证过程:对小项目而已是个轻量级的认证机制,符合开发需求: 二 jwt实现登陆认证流程 用户使用账号和面发出post请求 服务器接受到请求后使用私钥创建一个jwt,这边会生成token 服务器返回这个jwt给浏览器 浏览器需要将带有token的jwt放入请求头 每次手到客户端请求,服务器验证该jwt的token 验证成功返回

  • Springboot+SpringSecurity+JWT实现用户登录和权限认证示例

    如今,互联网项目对于安全的要求越来越严格,这就是对后端开发提出了更多的要求,目前比较成熟的几种大家比较熟悉的模式,像RBAC 基于角色权限的验证,shiro框架专门用于处理权限方面的,另一个比较流行的后端框架是Spring-Security,该框架提供了一整套比较成熟,也很完整的机制用于处理各类场景下的可以基于权限,资源路径,以及授权方面的解决方案,部分模块支持定制化,而且在和oauth2.0进行了很好的无缝连接,在移动互联网的授权认证方面有很强的优势,具体的使用大家可以结合自己的业务场景进行选

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

    1.添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjw

  • SpringBoot集成Spring Security用JWT令牌实现登录和鉴权的方法

    最近在做项目的过程中 需要用JWT做登录和鉴权 查了很多资料 都不甚详细 有的是需要在application.yml里进行jwt的配置 但我在导包后并没有相应的配置项 因而并不适用 在踩过很多坑之后 稍微整理了一下 做个笔记 一.概念 1.什么是JWT Json Web Token (JWT)是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准(RFC 7519) 该token被设计为紧凑且安全的 特别适用于分布式站点的单点登录(SSO)场景 随着JWT的出现 使得校验方式更加简单便

  • Springboot集成Spring Security实现JWT认证的步骤详解

    1 简介 Spring Security作为成熟且强大的安全框架,得到许多大厂的青睐.而作为前后端分离的SSO方案,JWT也在许多项目中应用.本文将介绍如何通过Spring Security实现JWT认证. 用户与服务器交互大概如下: 客户端获取JWT,一般通过POST方法把用户名/密码传给server: 服务端接收到客户端的请求后,会检验用户名/密码是否正确,如果正确则生成JWT并返回:不正确则返回错误: 客户端拿到JWT后,在有效期内都可以通过JWT来访问资源了,一般把JWT放在请求头:一次

  • SpringBoot集成Spring Security的方法

    至今Java能够如此的火爆Spring做出了很大的贡献,它的出现让Java程序的编写更为简单灵活,而Spring如今也形成了自己的生态圈,今天咱们探讨的是Spring旗下的一个款认证工具:SpringSecurity,如今认证框架主流"shiro"和"SpringSecurity",由于和Spring的无缝衔接,使用SpringSecurity的企业也越来越多. 1.Spring Security介绍 Spring security,是一个强大的和高度可定制的身份验

  • Springboot WebFlux集成Spring Security实现JWT认证的示例

    1 简介 在之前的文章<Springboot集成Spring Security实现JWT认证>讲解了如何在传统的Web项目中整合Spring Security和JWT,今天我们讲解如何在响应式WebFlux项目中整合.二者大体是相同的,主要区别在于Reactive WebFlux与传统Web的区别. 2 项目整合 引入必要的依赖: <dependency> <groupId>org.springframework.boot</groupId> <art

  • SpringBoot集成SpringSecurity和JWT做登陆鉴权的实现

    废话 目前流行的前后端分离让Java程序员可以更加专注的做好后台业务逻辑的功能实现,提供如返回Json格式的数据接口就可以.SpringBoot的易用性和对其他框架的高度集成,用来快速开发一个小型应用是最佳的选择. 一套前后端分离的后台项目,刚开始就要面对的就是登陆和授权的问题.这里提供一套方案供大家参考. 主要看点: 登陆后获取token,根据token来请求资源 根据用户角色来确定对资源的访问权限 统一异常处理 返回标准的Json格式数据 正文 首先是pom文件: <dependencies

  • SpringBoot整合Spring Security的详细教程

    好好学习,天天向上 本文已收录至我的Github仓库DayDayUP:github.com/RobodLee/DayDayUP,欢迎Star,更多文章请前往:目录导航 前言 Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架.提供了完善的认证机制和方法级的授权功能.是一款非常优秀的权限管理框架.它的核心是一组过滤器链,不同的功能经由不同的过滤器.这篇文章就是想通过一个小案例将Spring Security整合到SpringBoot中去.要实现的功能就是在认证服务器上

  • Spring Security+JWT实现认证与授权的实现

    目录 一.登录校验流程 1.Spring Security 完整流程 2.Spring Security的默认登陆验证流程. 3. 整合JWT大致流程 前端响应类 JWT工具类 重写UserDetailsService的方法 重写登录接口 认证过滤器 退出登陆 授权基本流程 限制访问资源所需权限 封装权限信息 RBAC权限模型 自定义失败处理 认证:验证当前访问系统的是不是本系统的用户,并且要确认具体是哪个用户 授权:经过认证后判断当前用户是否有权限进行某个操作 一.登录校验流程 1.Sprin

  • 详解Spring-Boot集成Spring session并存入redis

    spring Session 提供了一套用于管理用户 session 信息的API和实现. Spring Session为企业级Java应用的session管理带来了革新,使得以下的功能更加容易实现: 编写可水平扩展的原生云应用. 将session所保存的状态卸载到特定的外部session存储中,如Redis或Apache Geode中,它们能够以独立于应用服务器的方式提供高质量的集群. 当用户使用WebSocket发送请求的时候,能够保持HttpSession处于活跃状态. 在非Web请求的处

  • SpringBoot集成Spring Data JPA及读写分离

    相关代码: github OSCchina JPA是什么 JPA(Java Persistence API)是Sun官方提出的Java持久化规范,它为Java开发人员提供了一种对象/关联映射工具 来管理Java应用中的关系数据.它包括以下几方面的内容: 1.ORM映射 支持xml和注解方式建立实体与表之间的映射. 2.Java持久化API 定义了一些常用的CRUD接口,我们只需直接调用,而不需要考虑底层JDBC和SQL的细节. 3.JPQL查询语言 这是持久化操作中很重要的一个方面,通过面向对象

随机推荐