源码地址:https://gitee.com/TL0902/term/blob/929e16577549a1edba8da7a1212107f28799bd72/springsecurity/springbootsecurity.rar
对于开发一个网站,最重要的就是首先就是安全机制,还记得实训的时候javaweb手写登录拦截,权限控制的时候,很痛苦,原理很简单,代码很冗余,bug总不断,一不小心登录上来了,哈哈,这里呢简单使用下springsecurity这个框架,初学希望能带你入门,咱就不往深入探究,引领一下即可;
springsecurity出生名门,在spring大家族中,生态丰富,下面是官网;官网上都有使用方法,相信英语特别好的你已经去看官网教程了,安全框架其实不用过多介绍,你做出来的网站必须要有登录拦截吧,难道我直接越过login页面直接在地址栏输入index能到index页面吗,登录拦截,我们使用我的例子快速体验一下吧;
官网:https://spring.io/projects/spring-security
这里呢就不拿官网教程来说了,不要说我看不懂找不到,你找到了吗,在这里: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');
这里数据库是这样的:
再通过你自己的开发工具,导入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/即可看到这样,这里说一下页面不美观,但是功能到位就行:
我们点击登录,没有账号是不是,数据库都在我们手里了,还怕登录不上?总共有三个用户,同时也有不用权限,root—>ssvip权限,zhangsan—->svip权限,wangwu—>vip权限,可以看出我这里是一个权限优先级系统,密码这里都是用一个密码,数据库中是加密后的,都是‘root’,点击登录:
root用户,可以看到完整的功能:
注销,登录zhangsan用户,看不到ssvip功能:
注销,登录wangwu用户,只能看到vip功能:
分别具有不用的权限控制,以及登录控制;
首先我们使用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"); //设置登出页面
注释里很详细了已经,几个常用方法,慢慢了解吧;
大家有没有疑问,为什么这里表权限字段有一个ROLE_前缀,这个我卡bug了半天,在提问中有一个大佬帮助了我
那我们根据大佬的提示看一下源码,shift+shift搜一下这个类,可以看到这里确实是有一个前缀,学艺不精,感谢大佬,那我们不想加那个前缀,自定义注入下这个类,听大佬的方法即可:
这里就简单的介绍完了,希望对大家有帮助,这里只是使用默认的,当然这只是开始,后面我们想自定义service,这些资源都很丰富,还是那句话,引领一下即可;
看到这里了还不点个赞吗,关注下······也行啊