SpringSecurity + jwt + Oauth2实现动态权限管理(有源码)

目录

写在前面:强烈推荐查看大佬的文章13.Spring security权限管理

1.基于url的权限管理

1.1 建立用户表、角色表和路径表,并在数据库中插入对应关系

1.2 添加实体类

1.3 创建mapper

1.4 修改security相关类

1.5 自定义权限不足的异常处理器

1.6 postman测试

2.基于方法的权限管理

3.结尾


写在前面:强烈推荐查看大佬的文章13.Spring security权限管理

1.基于url的权限管理

1.1 建立用户表、角色表和路径表,并在数据库中插入对应关系

CREATE DATABASE SECURITY;
USE SECURITY;

CREATE TABLE USER(
	id INT PRIMARY KEY AUTO_INCREMENT,
	`username` VARCHAR(100) NOT NULL UNIQUE,
	`password` VARCHAR(100),
	role INT(11) NOT NULL DEFAULT 2,
	email VARCHAR(50),
	enabled TINYINT(1) DEFAULT 1,
	locked TINYINT(1) DEFAULT 0
)ENGINE INNODB DEFAULT CHARSET=utf8;

CREATE TABLE `menu` (
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`pattern` VARCHAR(128) DEFAULT NULL,
	PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;


CREATE TABLE `role` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(32) DEFAULT NULL,
  `nameZh` VARCHAR(32) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

CREATE TABLE `menu_role` (
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`mid` INT(11) DEFAULT NULL,
	`rid` INT(11) DEFAULT NULL,
	PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

CREATE TABLE `user_role` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `uid` INT(11) DEFAULT NULL,
  `rid` INT(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT INTO `menu` (`id`, `pattern`)
VALUES
	(1,'/admin/**'),
	(2,'/user1/**'),
	(3,'/visitor/**');
	
		
INSERT INTO `role` (`id`, `name`, `nameZh`)
VALUES
	(1,'ROLE_ADMIN','系统管理员'),
	(2,'ROLE_USER','普通用户'),
	(3,'ROLE_VISITOR','游客');
	
	
INSERT INTO `user` (`id`, `username`, `password`, `role`,`enabled`, `locked`)
VALUES
	(1,'admin','admin',1,1,0),
	(2,'user','user',2,1,0),
	(3,'visitor','visitor',3,1,0);

#第一个路径只能admin访问,第二个路径只能user访问,第三个路径只能vistor和user访问
INSERT INTO `menu_role` (`id`, `mid`, `rid`)
VALUES
	(1,1,1),
	(2,2,2),
	(3,3,3),
	(4,3,2);
#用户中role为1的既是管理员又是用户,role为2的为用户,role为3的是游客
INSERT INTO `user_role` (`id`, `uid`, `rid`)
VALUES
	(1,1,1),
	(2,1,2),
	(3,2,2),
	(4,3,3);	

        在security中,角色具有继承性,当一个用户同时拥有两个角色role时,他也同时具有两个role的访问权限。

1.2 添加实体类

        user类需要实现security的UserDetails接口,将用户对应的角色告诉security。该代码还实现的JSR303的参数校验,其中TinyInt(1)会被mybatis-plus自动转成boolean型,无需自定义注释。

package com.cg.springSecurity.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.cg.springSecurity.valid.AddGroup;
import com.cg.springSecurity.valid.UpdateGroup;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**

 * @author cg
 * @since 2022-05-13
 */
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("user")
public class User implements Serializable, UserDetails {

    private static final long serialVersionUID = 1L;


    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    @NotBlank(message = "用户名不能为空" , groups = {AddGroup.class})
    private String username;

    @NotBlank(message = "密码不能为空", groups = {AddGroup.class, UpdateGroup.class})
    private String password;

    @Email(message = "邮箱格式不正确!" , groups = AddGroup.class)
    private String email;

    private Integer role;

    private boolean enabled;

    private boolean locked;

    //一个用户有多个角色
    @TableField(exist = false)
    private List<Role> roles;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return roles.stream().map(r -> new SimpleGrantedAuthority(r.getName())).collect(Collectors.toList());
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return !locked;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return enabled;
    }
}
package com.cg.springSecurity.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.io.Serializable;

/**
 * @author cg
 * @date 2023/3/29 10:52
 */
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("role")
public class Role implements Serializable {
    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    private String name;

    private String nameZh;
}
package com.cg.springSecurity.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.io.Serializable;
import java.util.List;

/**
 * @author cg
 * @date 2023/3/29 10:55
 */
@Data
@TableName("menu")
public class Menu implements Serializable {
    private static final long serialVersionUID = 1L;

    @TableId(type = IdType.AUTO)
    private Integer id;

    private String pattern;

    @TableField(exist = false)
    //一个路径可以被多个角色访问
    private List<Role> roles;
}

1.3 创建mapper

package com.cg.springSecurity.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.cg.springSecurity.pojo.Role;
import com.cg.springSecurity.pojo.User;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * <p>
 * Mapper 接口
 * </p>
 *
 * @author cg
 * @since 2022-05-13
 */
public interface UserMapper extends BaseMapper<User> {
    User selectByName(@Param("name") String name);

    List<Role> getUserRolesByRole(@Param("role") Integer role);

    User getUserById(@Param("id") Integer id);
}
<?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.cg.springSecurity.mapper.UserMapper">

    <select id="selectByName" resultType="com.cg.springSecurity.pojo.User">
        SELECT * FROM security.user WHERE username = #{name};
    </select>

    <select id="getUserRolesByRole" resultType="com.cg.springSecurity.pojo.Role">
        SELECT  r.*
        FROM security.role r,security.user_role ur
        WHERE ur.uid = #{role} AND ur.`rid`=r.`id`;
    </select>

    <resultMap id="UserInfoMap" type="com.cg.springSecurity.pojo.User">
        <id property="id" column="id"/>
        <result property="username" column="username"/>
        <result property="password" column="password"/>
        <result property="email" column="email"/>
        <result property="enabled" column="enabled"/>
        <result property="locked" column="locked"/>
        <collection property="roles" ofType="com.cg.springSecurity.pojo.Role">
            <id column="rid" property="id"/>
            <result column="name" property="name"/>
            <result column="nameZh" property="nameZh"/>
        </collection>
    </resultMap>
    <select id="getUserById" resultMap="UserInfoMap">
        SELECT  u.* ,r.id as rid ,r.name ,r.nameZh
        FROM security.role r,security.user_role ur,security.`user` u
        WHERE u.role = #{id} AND ur.`rid`=r.`id` AND ur.`uid`=u.`id`;
    </select>
</mapper>
package com.cg.springSecurity.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.cg.springSecurity.pojo.User;

/**
 * <p>
 * Mapper 接口
 * </p>
 *
 * @author cg
 * @since 2022-05-13
 */
public interface RoleMapper extends BaseMapper<User> {

}
package com.cg.springSecurity.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.cg.springSecurity.pojo.Menu;
import com.cg.springSecurity.pojo.User;

import java.util.List;

/**
 * <p>
 * Mapper 接口
 * </p>
 *
 * @author cg
 * @since 2022-05-13
 */
public interface MenuMapper extends BaseMapper<User> {

    /**
     * @return 每一条路径中能访问该路径的所有角色
     */
    List<Menu> getAllMenu();
}
<?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.cg.springSecurity.mapper.MenuMapper">
    <resultMap id="MenuInfoMap" type="com.cg.springSecurity.pojo.Menu">
        <id property="id" column="mid"/>
        <result property="pattern" column="pattern"/>
        <collection property="roles" ofType="com.cg.springSecurity.pojo.Role">
            <id column="rid" property="id"/>
            <result column="name" property="name"/>
            <result column="nameZh" property="nameZh"/>
        </collection>
    </resultMap>
    <select id="getAllMenu" resultMap="MenuInfoMap">
        SELECT m.id AS mid,m.pattern,r.id AS rid ,r.name,r.nameZh
        FROM security.menu m , security.role r ,security.menu_role mr
        WHERE m.`id`=mr.`mid` AND mr.`rid` = r.`id`;
    </select>
</mapper>

1.4 修改security相关类

package com.cg.springSecurity.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cg.springSecurity.mapper.UserMapper;
import com.cg.springSecurity.pojo.User;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {

    @Resource
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws BadCredentialsException {
        
        //调用usersMapper方法,根据用户名查询数据库
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username",username);
        User user = userMapper.selectOne(wrapper);
        user.setPassword(new BCryptPasswordEncoder().encode(user.getPassword()));
        user.setRoles(userMapper.getUserRolesByRole(user.getRole()));
		//手动设置了role,也可以通过数据库查询获取
//        List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("admin");  //配置角色

        return user;
    }

}

  添加自定义的路径和权限映射

package com.cg.springSecurity.security;

import com.cg.springSecurity.mapper.MenuMapper;
import com.cg.springSecurity.pojo.Menu;
import com.cg.springSecurity.pojo.Role;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;

/**
 * SecurityMetadataSource接口负责提供受保护对象所需要的权限。由于该案例中,受保护对象所需要的权限保存在数据库中,所以可以通过自定义类继承自
 * FilterInvocationSecurityMetadataSource,并重写getAttributes方法来提供受保护对象所需要的权限。
 */
@Component
public class CustomSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
    @Resource
    MenuMapper menuMapper;

    AntPathMatcher antPathMatcher = new AntPathMatcher();

    /**
     * 在基于URL地址的权限控制中,受保护对象就是FilterInvocation。
     * @param object 受保护对象
     * @return 受保护对象所需要的权限
     */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        // 从受保护对象FilterInvocation中提取出当前请求的URI地址,例如/admin/hello
        String requestURI = ((FilterInvocation) object).getRequest().getRequestURI();
        // 查询所有菜单数据(每条数据中都包含访问该条记录所需要的权限)
        List<Menu> allMenu = menuMapper.getAllMenu();

        // 遍历菜单数据,如果当前请求的URL地址和菜单中某一条记录的pattern属性匹配上了(例如/admin/hello匹配上/admin/**)
        // 那么就可以获取当前请求所需要的权限;如果没有匹配上,则返回null。需要注意的是,如果AbstractSecurityInterceptor
        // 中的rejectPublicInvocations属性为false(默认值)时,则表示当getAttributes返回null时,允许访问受保护对象
        for (Menu menu : allMenu) {
            if (antPathMatcher.match(menu.getPattern(), requestURI)) {
                String[] roles = menu.getRoles().stream().map(Role::getName).toArray(String[]::new);
                return SecurityConfig.createList(roles);
            }
        }

        return null;
    }

    /**
     * 方便在项目启动阶段做校验,如果不需要校验,则直接返回null即可。
     * @return 所有的权限属性
     */
    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    /**
     * 表示当前对象支持处理的受保护对象是FilterInvocation。
     */
    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }
}

在配置文件中添加路径权限映射处理器

//添加自定义权限管理器
        ApplicationContext applicationContext = http.getSharedObject(ApplicationContext.class);
        http.apply(new UrlAuthorizationConfigurer<>(applicationContext))
                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O object) {
                        // 使用配置好的CustomSecurityMetadataSource来代替默认的SecurityMetadataSource对象
                        object.setSecurityMetadataSource(customSecurityMetadataSource);
                        // 将rejectPublicInvocations设置为true,表示当getAttributes返回null时,不允许访问受保护对象
                        object.setRejectPublicInvocations(false);
                        return object;
                    }
                });

1.5 自定义权限不足的异常处理器

package com.cg.springSecurity.security;

import com.cg.springSecurity.base.ResultInfo;
import com.google.gson.Gson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
    @Autowired
    private Gson gson;
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        //设置响应的类型和编码
        response.setHeader("Content-Type", "application/json;charset=utf-8");
        response.getWriter().write(gson.toJson(new ResultInfo<>(403, "error!", "权限不足")));
    }
}

http.formLogin()   //自定义自己编写的登陆页面
//                .loginPage("/login.html")  //登陆页面设置
                .loginProcessingUrl("/user/login")  //登陆访问路径
                .successHandler(authenticationSuccessHandler)
//                .defaultSuccessUrl("/success" , true) //登陆成功后跳转路径
//                .successForwardUrl("/")
//                .failureUrl("/user/fail")//登录失败跳转的路径
                .failureHandler(authenticationFailureHandler)
                .permitAll()
                .and().exceptionHandling()
                .accessDeniedHandler(accessDeniedHandler)
                .authenticationEntryPoint(authenticationEntryPoint)//登陆异常处理

1.6 postman测试

        添加测试controller

        

package com.cg.springSecurity.controller;

import com.cg.springSecurity.base.ResultInfo;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author cg
 * @date 2023/3/29 9:56
 */
@RestController
@CrossOrigin
public class IndexController {
    @GetMapping("/admin")
    public ResultInfo admin() {
        return new ResultInfo("这是管理员。。。。");
    }

    @GetMapping("/user1")
    public ResultInfo user() {
        return new ResultInfo("这是用户。。。。");
    }

    @GetMapping("/visitor")
    public ResultInfo visitor() {
        return new ResultInfo("这是游客。。。。");
    }

    @GetMapping("/other")
    public ResultInfo other() {
        return new ResultInfo("这是其他。。。。");
    }
}

登录游客 

可以访问游客 

 无法访问/user1

 

 可以访问未添加到url管理中的路径

由这一句代码来控制

// 将rejectPublicInvocations设置为true,表示当getAttributes返回null时,不允许访问受保护对象
                        object.setRejectPublicInvocations(false);

2.基于方法的权限管理

        耳熟能详的AOP,先在security的配置文件上开启该功能@EnableGlobalMethodSecurity,然后直接在方法上添加注释即可。这种方法对代码没用侵入性,这里就不做介绍了,有兴趣直接参考开头大佬的文章。

3.结尾

 gitee链接:springSecurity: springSecurity + Jwt + Oauth2实现登录模块

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
通用权限管理框架源码 2013-5-15更新功能: 1、菜单导航管理 2、操作按钮 3、角色管理 4、部门管理 5、用户管理(用户权限) 6、用户组管理(设置成员,用户组权限) 7、系统配置(动态配置系统参数) 8、附加属性(自定义属性) 9、系统日志(异常记录) 10、数据库备份/还原 11、资源管理,(动态数据库) 12、个人信息(基本信息,附加信息,用户角色,拥有权限) 13、首页快捷 14、数据回收站(业务功能删除过数据,全部保留在回收站) 15、系统个性化设置(切换菜单导航) 2012-9-10更新内容: 系统UI,给人感觉非常好,体积小巧,速度快 该源码是适用用于应用系统后台模块的管理(可扩展至支持集中化的权限管理平台), 0.支持N级菜单导航,菜单显示方式支持目前支持2种模式分别:菜单(无限级),横向(2级) 1.动态切换皮肤,目前有两狂UI 蓝色,咖啡色 2.表单验证,文本框高亮起来 3.可以动态分配权限按钮,分配角色权限,目录结构,栏目的链接都可以修改。权限管理非常灵活, 4.可以隐藏左侧导航栏,打开左侧导航栏,默认是打开,table表格都自应大小的 5.动态创建数据表,删除用户表,点击数据 表 可以查询字段信息 6.可以直接执行sql脚本 7.兼容 IE6,7,8,9 /Firefox /Google Chrome 这些浏览器都测试过 8.批量删除,自定义复选框样式,可以全选/反选 9.角色分级,集团和分公司的关系 10.权限 横向就是业务部分,具体负责哪块业务,纵向是级别 11.动态报表设置,并且可以导出Excel 12.登陆日记,操作日记,异常日记 13.海量批量删除数据库,调用公共存储过程,参数,表明,主键 特点: UI:传统html css,美观 漂亮 大方 实用 js框架:jquery 系统大部分使用AJAX操作。大大提高了用户体验 功能描述: 1.支持N级菜单导航,菜单显示方式支持目前支持2种模式分别: 菜单(无限级),横向(2级) 2.表单验证,文本框高亮起来 3.可以动态分配权限按钮,分配角色权限,目录结构,栏目的链接都可以修改。 4.可以隐藏左侧导航栏,打开左侧导航栏,默认是打开,table表格都自应大小的 5.动态创建数据表,删除用户表,点击数据 表 可以查询字段信息 6.可以直接执行sql脚本
权限管理 v1.0.8源码 源码描述: 其主要的功能就是,进行后台管理模块整合. 1)其可以支持多个应用,多个模块的权限管理. 2)支持Access和MsSql200/2005及Oracle9i以上. 3)采用角色来进行权限的授权,每个用户可以属于多个角色,享有交差权限. 4)整合方便,权限检测采用httpmodule方式检测.基本不用对原有程序进行修改,便可将原有程序进行整合. 5)可视化编辑,全新的Menu和Tab控件.支持拖拉式编辑. 6)统一的事件日志管理,所有登陆操作都有安全记录. 7)每个模块的每个栏目对应一个目录, 栏目的权限抽象分为(查看/新增/修改/删除/排序/打印/备用A/备用 8).目录里有一个web.config来进行目录文件权限配置,可直接将某个文件名设定到相对应的权限上. v1.0.8版更新记录 1.增加树状菜单样式,以适应多分类. 2.“查询”功能的地方,如果第一次查询后进行过翻页操作,再进行第二次的查询结果会停留在之前的页码处 3.Url地址权限判断,需要做长度对比.如设置defautl.aspx?cmd=122 则会自动匹配 defautl.aspx?cmd=122xxxxxxx 4.修改模块分类,提示请输入权限名称,其内容不可以为空 5.插入在线人员出错,重复值InsertOnlineUser 6.应用字段增加后,应用名称为输入框. 7.sys_FieldValueFromKey sys_FieldValueList 方法,排序为顺序acs 8.增加对应用的排序 9.增加操作日志删除和导出 10.date.js控件,选中当前日期返回值出错 11.登陆时,如已经登陆用户,点确认后直接登陆,不要让用户再重新输入用户名和密码 12.http://www.supesoft.com/bbs/disp.asp?B_T_ID=1313 13.修改默认同一ip登陆时出错次数为20次就禁止此ip登陆60分钟. 14.用户资料管理员,管理员只能管理自己部门下的用户(修改/删除) 15.后台增加禁止登陆ip限制.
Spring Security是一个主流的Java Web安全框架,它提供了许多现成的安全功能如身份认证、授权和攻击防护。基于Spring Security,我们可以构建出一个安全可靠的Web应用程序。JWT是一种轻量级的身份实体认证方法。在Web应用程序中,用户登录成功之后,服务器会颁发一个JWT令牌给客户端,客户端每次访问时需要携带这个JWT令牌,服务器通过验证JWT令牌的合法性来认证用户身份。OAuth2.0是一个授权框架,它定义了四种角色:资源所有者、客户端、授权服务器和资源服务器。在OAuth2.0框架下,资源服务器只有在通过授权服务器验证后,才会向客户端提供访问资源的权限。 Spring Security提供了对JWTOAuth2.0的支持。通过集成JWTOAuth2.0,我们可以构建出一个更加安全和灵活的Web应用程序。具体地,我们可以使用Spring SecurityJWT机制来实现用户身份认证,并使用OAuth2.0机制来实现对资源的授权。这意味着,我们可以通过Spring Security来管理应用程序中所有的安全相关事务,包括用户的认证和授权。 使用Spring SecurityJWTOAuth2.0,我们可以实现几种不同的认证和授权模式,例如,密码模式、授权码模式和刷新令牌模式等。每种模式都具有自己的使用场景和优缺点。例如,密码模式适用于Web应用程序需要进行用户身份认证的场景,而授权码模式适用于Web应用程序需要访问第三方资源的场景。 综上所述,Spring Security是一个强大的Java Web安全框架,它提供了许多功能,包括身份认证、授权和攻击防护等。使用Spring SecurityJWTOAuth2.0,我们可以实现更加安全和灵活的Web应用程序。通过选择不同的认证和授权模式,我们可以满足不同的使用场景和需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值