你知道怎么Spring security整合JWT么

模型分类 增加用户名和密码 基于内存的认证 导入依赖 创建一个 jwtuser 实现 userdetails 编写工具类生成令牌 编写拦截器 编写 userdetailsservice 的实现类 编写登录 最后配置 config 运行,返回 token 重写 usernamepasswordanthenticationfilter 配置 securityconfig 设计数据表 着重配置 springconfig 权限系统躲不开的概念,在shiro和spring security之间,你一般选啥?在前后端分离的项目中,你知道怎么spring security整合jwt么,来看看这篇文章哈!
思维导图如下:
rbac 全称为基于角色的权限控制,本段将会从什么是 rbac,模型分类,什么是权限,用户组的使用,实例分析等几个方面阐述 rbac.
思维导图
绘制思维导图如下什么是 rbac
rbac 全称为用户角色权限控制,通过角色关联用户,角色关联权限,这种方式,间阶的赋予用户的权限,如下图所示
对于通常的系统而言,存在多个用户具有相同的权限,在分配的时候,要为指定的用户分配相关的权限,修改的时候也要依次的对这几个用户的权限进行修改,有了角色这个权限,在修改权限的时候,只需要对角色进行修改,就可以实现相关的权限的修改。这样做增加了效率,减少了权限漏洞的发生。
模型分类 对于 rbac 模型来说,分为以下几个模型 分别是 rbac0,rbac1,rbac2,rbac3,这四个模型,这段将会依次介绍这四个模型,其中最常用的模型有 rbac0.
rbac0 rbac0 是最简单的 rbac 模型,这里面包含了两种。
用户和角色是多对一的关系,即一个用户只充当一种角色,一个角色可以有多个角色的担当。用户和角色是多对多的关系,即,一个用户可以同时充当多个角色,一个角色可以有多个用户。此系统功能单一,人员较少,这里举个栗子,张三既是行政,也负责财务,此时张三就有俩个权限,分别是行政权限,和财务权限两个部分。
rbac1 相对于 rbac0 模型来说,增加了子角色,引入了继承的概念。
rbac2 模型 这里 rbac2 模型,在 rbac0 模型的基础上,增加了一些功能,以及限制
角色互斥 即,同一个用户不能拥有两个互斥的角色,举个例子,在财务系统中,一个用户不能拥有会计员和审计这两种角色。
基数约束 即,用一个角色,所拥有的成员是固定的,例如对于 ceo 这种角色,同一个角色,也只能有一个用户。
先决条件 即,对于该角色来说,如果想要获得更高的角色,需要先获取低一级别的角色。举个栗子,对于副总经理和经理这两个权限来说,需要先有副总经理权限,才能拥有经理权限,其中副总经理权限是经理权限的先决条件。
运行时互斥 即,一个用户可以拥有两个角色,但是这俩个角色不能同时使用,需要切换角色才能进入另外一个角色。举个栗子,对于总经理和专员这两个角色,系统只能在一段时间,拥有其一个角色,不能同时对这两种角色进行操作。
rbac3 模型 即,rbac1,rbac2,两者模型全部累计,称为统一模型。
什么是权限 权限是资源的集合,这里的资源指的是软件中的所有的内容,即,对页面的操作权限,对页面的访问权限,对数据的增删查改的权限。举个栗子。对于下图中的系统而言,
拥有,计划管理,客户管理,合同管理,出入库通知单管理,粮食安全追溯,粮食统计查询,设备管理这几个页面,对这几个页面的访问,以及是否能够访问到菜单,都属于权限。
用户组的使用 对于用户组来说,是把众多的用户划分为一组,进行批量授予角色,即,批量授予权限。举个栗子,对于部门来说,一个部门拥有一万多个员工,这些员工都拥有相同的角色,如果没有用户组,可能需要一个个的授予相关的角色,在拥有了用户组以后,只需要,把这些用户全部划分为一组,然后对该组设置授予角色,就等同于对这些用户授予角色。
优点:减少工作量,便于理解,增加多级管理,等。
首先添加依赖
    org.springframework.boot    spring-boot-starter-security 然后添加相关的访问接口
package com.example.demo.web;import org.springframework.web.bind.annotation.requestmapping;import org.springframework.web.bind.annotation.restcontroller;@restcontroller@requestmapping(/test)public class test {    @requestmapping(/test)    public string test(){        return test;    }} 最后启动项目,在日志中查看相关的密码
访问接口,可以看到相关的登录界面
输入用户名和相关的密码
用户名:user密码 984cccf2-ba82-468e-a404-7d32123d0f9c 登录成功
基于 spring boot + mybatis plus + vue & element 实现的后台管理系统 + 用户小程序,支持 rbac 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
项目地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro 视频教程:https://doc.iocoder.cn/video/ 增加用户名和密码 在配置文件中,书写相关的登录和密码
spring:  security:    user:      name: ming      password: 123456      roles: admin 在登录页面,输入用户名和密码,即可正常登录
基于 spring cloud alibaba + gateway + nacos + rocketmq + vue & element 实现的后台管理系统 + 用户小程序,支持 rbac 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
项目地址:https://gitee.com/zhijiantianya/yudao-cloud 视频教程:https://doc.iocoder.cn/video/ 基于内存的认证 需要自定义类继承 websecurityconfigureradapter 代码如下
package com.example.demo.config;import org.springframework.context.annotation.bean;import org.springframework.context.annotation.configuration;import org.springframework.security.config.annotation.authentication.builders.authenticationmanagerbuilder;import org.springframework.security.config.annotation.web.configuration.websecurityconfigureradapter;import org.springframework.security.crypto.password.nooppasswordencoder;import org.springframework.security.crypto.password.passwordencoder;@configurationpublic class mywebsecurityconfig extends websecurityconfigureradapter {    @bean    passwordencoder passwordencoder(){        return nooppasswordencoder.getinstance();    }    @override    protected void configure(authenticationmanagerbuilder auth) throws exception {        auth.inmemoryauthentication()                .withuser(admin).password(123).roles(admin);    }} 即,配置的用户名为 admin,密码为 123,角色为 admin
httpsecurity
这里对一些方法进行拦截
package com.ming.demo.interceptor;@configuration@enablewebsecuritypublic class securityconfig  extends websecurityconfigureradapter {    @override    public void configure(authenticationmanagerbuilder auth) throws exception {        auth.inmemoryauthentication()                .withuser(itguang).password(123456).roles(user).and()                .withuser(admin).password({noop} + 123456).roles(admin);    }    @override    protected void configure(httpsecurity http) throws exception {        http.authorizerequests()                .anyrequest().permitall()                .and()                .formlogin()                .permitall()                .and()                .logout()                .permitall();    }} 即,这里完成了对所有的方法访问的拦截。
这是一个小 demo,目的,登录以后返回 jwt 生成的 token
导入依赖 添加 web 依赖
导入 jwt 和 security 依赖
   io.jsonwebtoken   jjwt   0.9.1   org.springframework.boot   spring-boot-starter-security   2.3.1.release 创建一个 jwtuser 实现 userdetails 创建 一个相关的 javabean
package com.example.demo;import org.springframework.security.core.grantedauthority;import org.springframework.security.core.userdetails.userdetails;import java.util.collection;public class jwtuser implements userdetails {    private string username;    private string password;    private integer state;    private collection authorities;    public jwtuser(){    }    public jwtuser(string username, string password, integer state, collection authorities){        this.username = username;        this.password = password;        this.state = state;        this.authorities = authorities;    }    @override    public collection getauthorities() {        return authorities;    }    @override    public string getpassword() {        return this.password;    }    @override    public string getusername() {        return this.username;    }    @override    public boolean isaccountnonexpired() {        return true;    }    @override    public boolean isaccountnonlocked() {        return true;    }    @override    public boolean iscredentialsnonexpired() {        return true;    }    @override    public boolean isenabled() {        return true;    }} 编写工具类生成令牌 编写工具类,用来生成 token,以及刷新 token,以及验证 token。
package com.example.demo;public class jwttokenutil implements serializable {    private string secret;    private long expiration;    private string header;    private string generatetoken(map claims) {        date expirationdate = new date(system.currenttimemillis() + expiration);        return jwts.builder().setclaims(claims).setexpiration(expirationdate).signwith(signaturealgorithm.hs512, secret).compact();    }    private claims getclaimsfromtoken(string token) {        claims claims;        try {            claims = jwts.parser().setsigningkey(secret).parseclaimsjws(token).getbody();        } catch (exception e) {            claims = null;        }        return claims;    }    public string generatetoken(userdetails userdetails) {        map claims = new hashmap(2);        claims.put(sub, userdetails.getusername());        claims.put(created, new date());        return generatetoken(claims);    }    public string getusernamefromtoken(string token) {        string username;        try {            claims claims = getclaimsfromtoken(token);            username = claims.getsubject();        } catch (exception e) {            username = null;        }        return username;    }    public boolean istokenexpired(string token) {        try {            claims claims = getclaimsfromtoken(token);            date expiration = claims.getexpiration();            return expiration.before(new date());        } catch (exception e) {            return false;        }    }    public string refreshtoken(string token) {        string refreshedtoken;        try {            claims claims = getclaimsfromtoken(token);            claims.put(created, new date());            refreshedtoken = generatetoken(claims);        } catch (exception e) {            refreshedtoken = null;        }        return refreshedtoken;    }    public boolean validatetoken(string token, userdetails userdetails) {        jwtuser user = (jwtuser) userdetails;        string username = getusernamefromtoken(token);        return (username.equals(user.getusername()) && !istokenexpired(token));    }} 编写拦截器 编写 filter 用来检测 jwt
package com.example.demo;@componentpublic class jwtauthenticationtokenfilter  extends onceperrequestfilter {    @autowired    private userdetailsservice userdetailsservice;    @autowired    private jwttokenutil jwttokenutil;    @override    protected void dofilterinternal(httpservletrequest httpservletrequest, httpservletresponse httpservletresponse, filterchain filterchain) throws servletexception, ioexception {        string authheader = httpservletrequest.getheader(jwttokenutil.getheader());        if (authheader != null && stringutils.isnotempty(authheader)) {            string username = jwttokenutil.getusernamefromtoken(authheader);            if (username != null && securitycontextholder.getcontext().getauthentication() == null) {                userdetails userdetails = this.userdetailsservice.loaduserbyusername(username);                if (jwttokenutil.validatetoken(authheader, userdetails)) {                    usernamepasswordauthenticationtoken authentication =                    new usernamepasswordauthenticationtoken(userdetails,null,userdetails.getauthorities());                    authentication.setdetails(new webauthenticationdetailssource().builddetails(httpservletrequest));                    securitycontextholder.getcontext().setauthentication(authentication);                }            }        }        filterchain.dofilter(httpservletrequest, httpservletresponse);    }} 编写 userdetailsservice 的实现类 在上方代码中,编写 userdetailsservice,类,实现其验证过程
package com.example.demo;@servicepublic class jwtuserdetailsserviceimpl  implements userdetailsservice {    @autowired    private usermapper usermapper;    @override    public userdetails loaduserbyusername(string s) throws usernamenotfoundexception {        user user = usermapper.selectbyusername(s);        if (user == null) {            throw new usernamenotfoundexception(string.format('%s'.这个用户不存在, s));        }        list collect = user.getroles().stream().map(role::new).collect(collectors.tolist());        return new jwtuser(user.getusername(), user.getpassword(), user.getstate(), collect);    }} 编写登录 编写登录业务的实现类 其 login 方法会返回一个 jwtutils 的 token
@servicepublic class userserviceimpl  implements userservice {    @autowired    private usermapper usermapper;    @autowired    private authenticationmanager authenticationmanager;    @autowired    private userdetailsservice userdetailsservice;    @autowired    private jwttokenutil jwttokenutil;    public user findbyusername(string username) {        user user = usermapper.selectbyusername(username);        return user;    }    public retresult login(string username, string password) throws authenticationexception {        usernamepasswordauthenticationtoken uptoken = new usernamepasswordauthenticationtoken(username, password);        final authentication authentication = authenticationmanager.authenticate(uptoken);        securitycontextholder.getcontext().setauthentication(authentication);        userdetails userdetails = userdetailsservice.loaduserbyusername(username);        return new retresult(retcode.success.getcode(),jwttokenutil.generatetoken(userdetails));    }} 最后配置 config @enableglobalmethodsecurity(prepostenabled = true)@enablewebsecuritypublic class websecurity extends websecurityconfigureradapter {    @autowired    private userdetailsservice userdetailsservice;    @autowired    private jwtauthenticationtokenfilter jwtauthenticationtokenfilter;    @autowired    public void configureauthentication(authenticationmanagerbuilder authenticationmanagerbuilder) throws exception {        authenticationmanagerbuilder.userdetailsservice(this.userdetailsservice).passwordencoder(passwordencoder());    }    @bean(name = beanids.authentication_manager)    @override    public authenticationmanager authenticationmanagerbean() throws exception {        return super.authenticationmanagerbean();    }    @bean    public passwordencoder passwordencoder() {        return new bcryptpasswordencoder();    }    @override    protected void configure(httpsecurity http) throws exception {        http.csrf().disable().sessionmanagement().sessioncreationpolicy(sessioncreationpolicy.stateless)                .and().authorizerequests()                .antmatchers(httpmethod.options, /**).permitall()                .antmatchers(/auth/**).permitall()                .anyrequest().authenticated()                .and().headers().cachecontrol();        http.addfilterbefore(jwtauthenticationtokenfilter, usernamepasswordauthenticationfilter.class);        expressionurlauthorizationconfigurer.expressionintercepturlregistry registry = http.authorizerequests();        registry.requestmatchers(corsutils::ispreflightrequest).permitall();    }    @bean    public corsfilter corsfilter() {        final urlbasedcorsconfigurationsource urlbasedcorsconfigurationsource = new urlbasedcorsconfigurationsource();        final corsconfiguration cors = new corsconfiguration();        cors.setallowcredentials(true);        cors.addallowedorigin(*);        cors.addallowedheader(*);        cors.addallowedmethod(*);        urlbasedcorsconfigurationsource.registercorsconfiguration(/**, cors);        return new corsfilter(urlbasedcorsconfigurationsource);    }} 运行,返回 token 运行,返回结果为 token
这里配置 springsecurity 之 json 登录
这里需要重写 usernamepasswordanthenticationfilter 类,以及配置 springsecurity
重写 usernamepasswordanthenticationfilter public class customauthenticationfilter extends usernamepasswordauthenticationfilter {    @override    public authentication attemptauthentication(httpservletrequest request, httpservletresponse response) throws authenticationexception {        if(request.getcontenttype().equals(mediatype.application_json_utf8_value)                ||request.getcontenttype().equals(mediatype.application_json_value)){            objectmapper mapper = new objectmapper();            usernamepasswordauthenticationtoken authrequest = null;            try (inputstream is = request.getinputstream()){                authenticationbean authenticationbean = mapper.readvalue(is,authenticationbean.class);                authrequest = new usernamepasswordauthenticationtoken(                        authenticationbean.getusername(), authenticationbean.getpassword());            }catch (ioexception e) {                e.printstacktrace();                authrequest = new usernamepasswordauthenticationtoken(                        , );            }finally {                setdetails(request, authrequest);                return this.getauthenticationmanager().authenticate(authrequest);            }        }        else {            return super.attemptauthentication(request, response);        }    }} 配置 securityconfig @overrideprotected void configure(httpsecurity http) throws exception {    http            .cors().and()            .antmatcher(/**).authorizerequests()            .antmatchers(/, /login**).permitall()            .anyrequest().authenticated()            .and().formlogin().loginpage(/)            .and().csrf().disable();    http.addfilterat(customauthenticationfilter(),    usernamepasswordauthenticationfilter.class);}@beancustomauthenticationfilter customauthenticationfilter() throws exception {    customauthenticationfilter filter = new customauthenticationfilter();    filter.setauthenticationsuccesshandler(new successhandler());    filter.setauthenticationfailurehandler(new failurehandler());    filter.setfilterprocessesurl(/login/self);    filter.setauthenticationmanager(authenticationmanagerbean());    return filter;} 这样就完成使用 json 登录 springsecurity
需要在 config 类中配置如下内容
@bean  public bcryptpasswordencoder passwordencoder(){      return new bcryptpasswordencoder();  } 即,使用此方法,对密码进行加密, 在业务层的时候,使用此加密的方法
@service@transactionalpublic class userserviceimpl implements userservice {    @resource    private userrepository userrepository;    @resource    private bcryptpasswordencoder bcryptpasswordencoder;    @override    public user add(user user) {        user.setpassword(bcryptpasswordencoder.encode(user.getpassword()));        user user2 = userrepository.save(user);        return user2;    }    @override    public resultinfo login(user user) {        resultinfo resultinfo=new resultinfo();        user user2 = userrepository.findbyname(user.getname());        if (user2==null) {            resultinfo.setcode(-1);            resultinfo.setmessage(用户名不存在);            return resultinfo;        }        if (!bcryptpasswordencoder.matches(user.getpassword(),user2.getpassword())) {            resultinfo.setcode(-1);            resultinfo.setmessage(密码不正确);            return resultinfo;        }        resultinfo.setmessage(登录成功);        return resultinfo;    }} 即,使用 bcryptpasswordencoder 对密码进行加密,保存数据库
这里使用数据库认证 springsecurity
设计数据表 这里设计数据表
着重配置 springconfig @configurablepublic class websecurityconfig extends websecurityconfigureradapter {    @autowired    private userservice userservice;    @bean    passwordencoder passwordencoder(){        return new bcryptpasswordencoder();    }    @override    protected void configure(authenticationmanagerbuilder auth) throws exception {        auth.userdetailsservice(userservice);    }    @override    protected void configure(httpsecurity http) throws exception {        http.authorizerequests()                .antmatchers(/admin/**).hasrole(admin)                .anyrequest().authenticated()                .and()                .formlogin()                .loginprocessingurl(/login).permitall()                .and()                .csrf().disable();    }} 这里着重配置 springconfig。
着重讲解了 rbac 的权限配置,以及简单的使用 springsecurity,以及使用 springsecurity + jwt 完成前后端的分离,以及配置 json 登录,和密码加密方式。

现在入手iPhone11还是iPhone12?
卢伟冰发表Redmi品牌独立宣言 死磕品质追求极致性价比
科瑞技术最新升级的切叠一体机首次亮相
华润微:在手订单饱满,多个业务板块齐头并进
高通加速布局VR/无人机 物联网时代能否复制辉煌
你知道怎么Spring security整合JWT么
一款十分强大的文件加密解密CLI工具toplip的详细资料概述
简要概述LoRa技术在智慧工厂的应用
为什么多数人会选择购买贴片电阻
万用表9V电池代换电路,1.5 to 9v dc-dc converter
最具有性价比降噪蓝牙耳机,学生党最值得推荐的耳机排名
浅析用几何描绘物理学的统一理论
柏科数据与宁算科技,联合建设“西部高原数据湖”
数字化转型的主要方向是什么
限幅电路的工作原理
思科宣布将2.71亿美元现金收购Lightwire
重磅!英国:华为确实存在风险!
马斯克:特斯拉的目标是最终达到每年生产2000万辆电动汽车
电力脱硫湿式球磨机主轴磨损了?这种免拆卸的修复方法用过的都说好
电气工程施工阶段的质量控制措施