广告位联系
返回顶部
分享到

SpringSecurity+jwt+captcha登录认证授权流程总结

java 来源:互联网 作者:佚名 发布时间:2024-11-16 10:42:56 人浏览
摘要

SpringSecurity+jwt+captcha登录认证授权总结 版本信息: springboot 3.2.0、springSecurity 6.2.0、mybatis-plus 3.5.5 认证授权思路和流程: 未携带token,访问登录接口: 1、用户登录携带账号密码 2、请求到达自

SpringSecurity+jwt+captcha登录认证授权总结

版本信息:

springboot 3.2.0、springSecurity 6.2.0、mybatis-plus 3.5.5

认证授权思路和流程: 未携带token,访问登录接口:

1、用户登录携带账号密码

2、请求到达自定义Filter,自定义Filter(如JwtAuthenticationTokenFilter)继承OncePerRequestFilter(此Filter只会进行一次过滤,在请求返回时,不会再进行调用),在SecurityConfig中配置,将自定义Filter添加到过滤器链中并加在UsernamePasswordAuthenticationFilter过滤器之前

3、自定义Filter逻辑

3.1、查询到用户未携带token,直接放行,进入到后面认证流程

3.2、将用户信息封装成Authentication对象,调用authticate()方法进行验证,一直到DaoAuthenticationProvider中,会调用UserDetailService的loadUserByUserName()方法;自定义UserDetailServiceImpl继承UserDetailService接口;重写其loadUserByUserName()方法;查到用户后,封装成UserDetail对象返回

4、调用passwordEncoder的验证方法进行用户信息的认证(一般使用BCryptPasswordEncoder,创建此Bean并放入容器中)

5、认证通过后,使用JWT创建token并放到redis中;返回token到前端

携带token访问:

1、请求到达自定义Filter中,获取token,先验证token的正确性,从token中获取到userId,根据userId从redis中获取用户信息,将用户信息封装成Authentication对象,放进SecurityContextHolder中,后面的过滤器会在SecurityContextHolder中获取用户的信息

2、请求到达FilterSecurityInterceptor,在springSecurity中默认使用FilterSecurityInterceptor来进行权限校验;FilterSecurityInterceptor会从SecurityContextHolder中获取Authentication,然后获取其中的权限信息,判断当前用户是否拥有当前资源的访问权限;

3、通过权限判断,获取资源返回给前端;

登录认证流程图:

基于RBAC的授权控制: RBAC概念:

Role-Based Access Control,中文意思是:基于角色(Role)的访问控制。这是一种广泛应用于计算机系统和网络安全领域的访问控制模型。

简单来说,就是通过将权限分配给角色,再将角色分配给用户,来实现对系统资源的访问控制。一个用户拥有若干角色,每一个角色拥有若干权限。这样,就构造成“用户-角色-权限”的授权模型。在这种模型中,用户与角色之间,角色与权限之间,一般是多对多的关系

模型:

在数据库中主要体现用户表、角色表、菜单表、用户角色关联表、角色菜单关联表五个模型:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

CREATE TABLE "mySchema"."t_user"

(

"id" INT IDENTITY(1, 1) NOT NULL,

"username" VARCHAR(100) NOT NULL,

"password" VARCHAR(100) NOT NULL,

"email" VARCHAR(100) NOT NULL,

"phone" VARCHAR(100),

UNIQUE("id"),

UNIQUE("username"),

UNIQUE("email"),

UNIQUE("phone"),

NOT CLUSTER PRIMARY KEY("id")) STORAGE(ON "MAIN", CLUSTERBTR) ;

COMMENT ON TABLE "mySchema"."t_user" IS '用户表';

COMMENT ON COLUMN "mySchema"."t_user"."id" IS '用户id';

COMMENT ON COLUMN "mySchema"."t_user"."username" IS '用户名';

COMMENT ON COLUMN "mySchema"."t_user"."password" IS '密码';

COMMENT ON COLUMN "mySchema"."t_user"."email" IS '用户邮箱';

COMMENT ON COLUMN "mySchema"."t_user"."phone" IS '电话';

CREATE TABLE "mySchema"."sys_role"

(

"id" BIGINT IDENTITY(1, 1) NOT NULL,

"name" VARCHAR(128) DEFAULT NULL,

"role_key" VARCHAR(100) DEFAULT NULL,

"status" CHAR(1) DEFAULT '0',

"del_flag" INT DEFAULT 0,

"create_by" BIGINT DEFAULT NULL,

"create_time" DATETIME(6) DEFAULT NULL,

"update_by" BIGINT DEFAULT NULL,

"update_time" DATETIME(6) DEFAULT NULL,

"remark" VARCHAR(500) DEFAULT NULL,

NOT CLUSTER PRIMARY KEY("id")) STORAGE(ON "MAIN", CLUSTERBTR) ;

COMMENT ON TABLE "mySchema"."sys_role" IS '角色表';

COMMENT ON COLUMN "mySchema"."sys_role"."id" IS '角色id';

COMMENT ON COLUMN "mySchema"."sys_role"."name" IS '角色名称';

COMMENT ON COLUMN "mySchema"."sys_role"."role_key" IS '角色权限字符串';

COMMENT ON COLUMN "mySchema"."sys_role"."status" IS '角色状态(0正常, 1停用)';

COMMENT ON COLUMN "mySchema"."sys_role"."del_flag" IS '删除标志(0未删除,1已删除)';

COMMENT ON COLUMN "mySchema"."sys_role"."remark" IS '备注';

CREATE TABLE "mySchema"."sys_menu"

(

"id" BIGINT IDENTITY(2, 1) NOT NULL,

"menu_name" VARCHAR(64) DEFAULT 'NULL' NOT NULL,

"path" VARCHAR(200) DEFAULT NULL,

"component" VARCHAR(50) DEFAULT NULL,

"visible" CHAR(1) DEFAULT '0',

"status" CHAR(1) DEFAULT '0',

"perms" VARCHAR(100) DEFAULT NULL,

"icon" VARCHAR(100) DEFAULT '#',

"create_by" BIGINT DEFAULT NULL,

"create_time" DATETIME(6) DEFAULT CURRENT_TIMESTAMP,

"update_by" BIGINT DEFAULT NULL,

"update_time" DATETIME(6) DEFAULT CURRENT_TIMESTAMP,

"delete_f1ag" INT DEFAULT 0,

"remark" VARCHAR(500) DEFAULT NULL,

UNIQUE("id"),

NOT CLUSTER PRIMARY KEY("id")) STORAGE(ON "MAIN", CLUSTERBTR) ;

COMMENT ON TABLE "mySchema"."sys_menu" IS '菜单表';

COMMENT ON COLUMN "mySchema"."sys_menu"."menu_name" IS '菜单名';

COMMENT ON COLUMN "mySchema"."sys_menu"."path" IS '路由地址';

COMMENT ON COLUMN "mySchema"."sys_menu"."component" IS '组件路径';

COMMENT ON COLUMN "mySchema"."sys_menu"."visible" IS '菜单状态(0显示1隐藏)';

COMMENT ON COLUMN "mySchema"."sys_menu"."status" IS '菜单状态(0正常1停用)';

COMMENT ON COLUMN "mySchema"."sys_menu"."perms" IS '权限标识';

COMMENT ON COLUMN "mySchema"."sys_menu"."icon" IS '菜单图标';

COMMENT ON COLUMN "mySchema"."sys_menu"."delete_f1ag" IS '是否删除(0未删除1已删除)';

COMMENT ON COLUMN "mySchema"."sys_menu"."remark" IS '备注';

CREATE TABLE "mySchema"."sys_user_role"

(

"user_id" BIGINT DEFAULT 0 NOT NULL,

"role_id" BIGINT DEFAULT 0 NOT NULL,

NOT CLUSTER PRIMARY KEY("user_id", "role_id")) STORAGE(ON "MAIN", CLUSTERBTR) ;

COMMENT ON TABLE "mySchema"."sys_user_role" IS '用户角色表';

COMMENT ON COLUMN "mySchema"."sys_user_role"."user_id" IS '用户id';

COMMENT ON COLUMN "mySchema"."sys_user_role"."role_id" IS '角色id';

CREATE TABLE "mySchema"."sys_role_menu"

(

"role_id" BIGINT DEFAULT 0 NOT NULL,

"menu_id" BIGINT DEFAULT 0 NOT NULL,

NOT CLUSTER PRIMARY KEY("role_id", "menu_id")) STORAGE(ON "MAIN", CLUSTERBTR) ;

COMMENT ON TABLE "mySchema"."sys_role_menu" IS '角色菜单关联表';

COMMENT ON COLUMN "mySchema"."sys_role_menu"."role_id" IS '角色id';

COMMENT ON COLUMN "mySchema"."sys_role_menu"."menu_id" IS '菜单id';

权限流程:

用户表、角色表、菜单表、部门表、用户角色关联表、角色菜单关联表;数据权限分为5种:个人、全部、本部门、指定部门、本部门及以下
链路:

1、用户注册,指定部门;创建角色,给角色赋菜单权限、数据权限;给用户赋予角色;
2、用户登录,通过用户的所有角色,获取所有的菜单权限和最大数据权限;菜单数据直接展示在页面;所有数据都有创建人,则数据的部门id是创建人的部门id;
3、在访问数据接口时,通过mybatis的拦截器对用户的数据进行过滤(拼接sql),返回给前端;

captcha图片验证码:

实现思路:

1、图片验证码获取,并将验证码验证码存放起来(单机应用可放在session中,分布式应用放在redis中)

2、当用户登录时,携带验证码以及验证码的key,进入到后端从redis中获取值进行验证

1

2

3

4

5

6

<!-- 谷歌kaptcha验证码依赖 -->

<dependency>

    <groupId>com.github.penggle</groupId>

    <artifactId>kaptcha</artifactId>

    <version>2.3.2</version>

</dependency>

代码思路:

1、生成验证码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

public Result<CaptchaVO> getCaptcha() throws IOException {

    // 生成文字验证码

    String content = defaultKaptcha.createText();

    // 生成图片验证码

    ByteArrayOutputStream outputStream = null;

    BufferedImage image = defaultKaptcha.createImage(content);

    outputStream = new ByteArrayOutputStream();

    ImageIO.write(image, "jpg", outputStream);

    // 对字节数组Base64编码

    String str = "data:image/jpeg;base64,";

    String base64Img = str + Base64.getEncoder().encodeToString(outputStream.toByteArray()).replace("\n", "").replace("\r", "");

    CaptchaVO captchaVO = captchaService.cacheCaptcha(content);

    captchaVO.setBase64Img(base64Img);

    return Result.success(captchaVO);

}

2、存储验证码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

@Service

public class CaptchaService {

    private Long timeout = 300L;

    @Autowired

    private RedisUtils redisUtils;

    private final String CAPTCHA_KEY_PREFIX = "captcha:verification:";

    public CaptchaVO cacheCaptcha(String captcha){

        //生成一个随机标识符

        String randomStr = UUID.randomUUID().toString();

        //缓存验证码并设置过期时间

        String captchaKey = CAPTCHA_KEY_PREFIX.concat(randomStr);

        redisUtils.set(captchaKey, captcha, timeout, TimeUnit.SECONDS);

        CaptchaVO captchaVO = new CaptchaVO();

        captchaVO.setCaptchaKey(captchaKey);

        captchaVO.setExpire(timeout);

        captchaVO.setCaptcha(captcha);

        return captchaVO;

    }

}

3、校验验证码

1

2

3

4

5

6

7

Object captcha = redisUtils.get(reqVO.getCaptchaKey());

if (Objects.isNull(captcha)) {

    return "验证码已过期";

}

if (!captcha.equals(reqVO.getCaptcha())) {

    return "验证码错误";

}


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 :
相关文章
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计