看完这一篇你还不会springsecurity吗?springsecurity小实例,简单实现网站登录获权(附源码)

springsecurity小实例,简单实现网站登录获权(附源码)

源码地址:https://gitee.com/TL0902/term/blob/929e16577549a1edba8da7a1212107f28799bd72/springsecurity/springbootsecurity.rar

前言

对于开发一个网站,最重要的就是首先就是安全机制,还记得实训的时候javaweb手写登录拦截,权限控制的时候,很痛苦,原理很简单,代码很冗余,bug总不断,一不小心登录上来了,哈哈,这里呢简单使用下springsecurity这个框架,初学希望能带你入门,咱就不往深入探究,引领一下即可;

介绍

springsecurity出生名门,在spring大家族中,生态丰富,下面是官网;官网上都有使用方法,相信英语特别好的你已经去看官网教程了,安全框架其实不用过多介绍,你做出来的网站必须要有登录拦截吧,难道我直接越过login页面直接在地址栏输入index能到index页面吗,登录拦截,我们使用我的例子快速体验一下吧;

官网:https://spring.io/projects/spring-security

看完这一篇你还不会springsecurity吗?springsecurity小实例,简单实现网站登录获权(附源码)_第1张图片

这里呢就不拿官网教程来说了,不要说我看不懂找不到,你找到了吗,在这里:https://spring.io/guides/topicals/spring-security-architecture/

体验上手

环境说明:JDK8,idea工具,maven项目,mysql8;

再次出现源码地址:https://gitee.com/TL0902/term/blob/929e16577549a1edba8da7a1212107f28799bd72/springsecurity/springbootsecurity.rar

这里我们拿到代码,首先构造数据库,执行user.sql文件,或者直接去运行sql命令:


SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for users
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `user_id` int(20) NOT NULL,
  `user_name` varchar(20) NOT NULL,
  `user_password` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `user_role` varchar(20) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- ----------------------------
-- Records of users
-- ----------------------------
INSERT INTO `users` VALUES ('1', 'root', '$2a$10$7TmcLHU8oRDCppvWXuy6o.cocm6w2PDMxoHqwE5Dy.w7HRcrCzPPG', 'ROLE_ssvip');
INSERT INTO `users` VALUES ('2', 'zhangsan', '$2a$10$7TmcLHU8oRDCppvWXuy6o.cocm6w2PDMxoHqwE5Dy.w7HRcrCzPPG', 'ROLE_svip');
INSERT INTO `users` VALUES ('3', 'wangwu', '$2a$10$7TmcLHU8oRDCppvWXuy6o.cocm6w2PDMxoHqwE5Dy.w7HRcrCzPPG', 'ROLE_vip');

这里数据库是这样的:

看完这一篇你还不会springsecurity吗?springsecurity小实例,简单实现网站登录获权(附源码)_第2张图片

再通过你自己的开发工具,导入maven项目,修改application.properties中连接数据库的用户名和密码:

spring.datasource.username=你的用户名
spring.datasource.password=你的密码
spring.datasource.url=jdbc:mysql://localhost:3306/你使用的的数据库?useUnicode=true&zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=utf-8

就可以启动项目了,打开浏览器地址栏输入http://localhost:8888/即可看到这样,这里说一下页面不美观,但是功能到位就行:

看完这一篇你还不会springsecurity吗?springsecurity小实例,简单实现网站登录获权(附源码)_第3张图片

我们点击登录,没有账号是不是,数据库都在我们手里了,还怕登录不上?总共有三个用户,同时也有不用权限,root—>ssvip权限,zhangsan—->svip权限,wangwu—>vip权限,可以看出我这里是一个权限优先级系统,密码这里都是用一个密码,数据库中是加密后的,都是‘root’,点击登录:

root用户,可以看到完整的功能:

看完这一篇你还不会springsecurity吗?springsecurity小实例,简单实现网站登录获权(附源码)_第4张图片

注销,登录zhangsan用户,看不到ssvip功能:

看完这一篇你还不会springsecurity吗?springsecurity小实例,简单实现网站登录获权(附源码)_第5张图片

注销,登录wangwu用户,只能看到vip功能:

看完这一篇你还不会springsecurity吗?springsecurity小实例,简单实现网站登录获权(附源码)_第6张图片

分别具有不用的权限控制,以及登录控制;

代码解析

认证和授权

首先我们使用springsecurity需要开启认证和授权功能,就是这段代码:

http
    .authorizeRequests()
    .antMatchers("/").permitAll()
    .antMatchers("/user/vip").hasAnyRole("vip","svip","ssvip")              //给角色授权
    .antMatchers("/user/svip").hasAnyRole("svip","ssvip")
    .antMatchers("/user/**").hasRole("ssvip")
    .and()
    .csrf().disable();

对不同的路径进行授权,这需要注意一点,就是我刚开始做的时候想法的错误,bug了半天,我之前的代码思路是这样的:

http
    .authorizeRequests()
    .antMatchers("/").permitAll()
    .antMatchers("/user/vip").hasRole("vip")              //给角色授权
    .antMatchers("/user/svip","/user/vip").hasRole("svip")
    .antMatchers("/user/**").hasRole("ssvip")
    .and()
    .csrf().disable();

是不是好像也没错哈,这样是不对的,这样那天我发现只能访问ssvip,因为这里你访问"/user/vip"他会先看你有没有vip权限,然后再看你有没有svip权限,那我们数据库角色里只给了svip权限自然不能访问,同样的道理,访问"/user/svip"路径,你又不具备vip权限,就也是403不能访问,那这个思路是错误的,虽然可以这么理解,但是代码不允许哦;这可能就是不同的人不同的想法与思路;

注销

登录上肯定要有注销,很简单,只需要访问logout就可以实现注销就可以;

权限控制

这里我们使用的都是springsecurity默认的,当然可以自定义,网上都是自定义的,还是入门你看我,引领一下即可

权限控制是一个重点,实现有两种方式:

1、基于内存

就是在内存中写死数据,数据就会在内存中,然后获得用户登录后的数据,与你在内存中的数据对比,比如一个校级管理系统,平时只有校长和主任使用,你当然可以写死几个账号在内存中,也不需要浪费数据库;但是你千万不要通过数据查询出来,都在内存里,服务器想爆炸吗!

基于内存代码,源码中我注释了,很简单一看就懂吧:

 auth
     .inMemoryAuthentication()
     .passwordEncoder(new BCryptPasswordEncoder())//在此处应用自定义PasswordEncoder
     .withUser("root")
     .password(new BCryptPasswordEncoder().encode("root"))
     .roles("ssvip")
     .and()
     .withUser("user")
     .password(new BCryptPasswordEncoder().encode("user"))
     .roles("vip");

还有一个就是这个,进行密码加密,这里使用的是springsecurity自带的一个密码加密,也是springsrcurity官方推荐,注入进来即可使用:

@Bean
public  BCryptPasswordEncoder BCryptPasswordEncoder(){
    return new BCryptPasswordEncoder();
}

2、基于数据库

看代码:

//注入dataSource
 @Autowired
    DataSource dataSource;

auth.jdbcAuthentication()
                .dataSource(dataSource)
                .usersByUsernameQuery("select user_name,user_password, 'true' as enabled from users WHERE user_name=?")  //认证
                .authoritiesByUsernameQuery("select user_name,user_role from users where user_name=?")     //授权
                .passwordEncoder(new BCryptPasswordEncoder());   //编码方式

这里说一下sql语句,为什么这么写,第一个usersByUsernameQuery()我们就是要查询账号密码,但是为什么加一个'true' as enabled这是指定此用户开启,false呢就是锁定用户,用户不能使用,我这里没有写在数据库中,做提醒作用,这里告诉大家在设计数据库的时候要设立一个enabled字段;

authoritiesByUsernameQuery()需要查询,用户名和用户名的权限即可,最后是编码方式;

记住我和登录页

记住我就是当我们关闭浏览器,再打开同一网站发现自己还是有登录状态,这就是记住我,只需要很简单一句代码即可;

http.rememberMe();   //开启记住我

//这里说一下,springsecurity有自己默认的登录页面,如果不自定义,那个比我这个好看,那我们开发完肯定使用自己的登录页,所以这是使用自己登录页的方法,其实usernameParameter和passwordParameter是你设置的登录表单中账号密码对用的name
//没有权限默认到登录页面。需要开启登录页面
http.formLogin().usernameParameter("name").passwordParameter("password").loginPage("/tologin");
http.logout().logoutSuccessUrl("/index");   //设置登出页面

springsecurity整合thymeleaf

注释里很详细了已经,几个常用方法,慢慢了解吧;

小问题

大家有没有疑问,为什么这里表权限字段有一个ROLE_前缀,这个我卡bug了半天,在提问中有一个大佬帮助了我

看完这一篇你还不会springsecurity吗?springsecurity小实例,简单实现网站登录获权(附源码)_第7张图片

看完这一篇你还不会springsecurity吗?springsecurity小实例,简单实现网站登录获权(附源码)_第8张图片

那我们根据大佬的提示看一下源码,shift+shift搜一下这个类,可以看到这里确实是有一个前缀,学艺不精,感谢大佬,那我们不想加那个前缀,自定义注入下这个类,听大佬的方法即可:

看完这一篇你还不会springsecurity吗?springsecurity小实例,简单实现网站登录获权(附源码)_第9张图片

小结

这里就简单的介绍完了,希望对大家有帮助,这里只是使用默认的,当然这只是开始,后面我们想自定义service,这些资源都很丰富,还是那句话,引领一下即可;

看到这里了还不点个赞吗,关注下······也行啊

你可能感兴趣的:(小实例,springboot,spring大家族,spring,springboot,系统安全)