Spring Boot中使用 Spring Security 构建权限系统的示例代码
spring security是一个能够为基于spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在spring应用上下文中配置的bean,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
权限控制是非常常见的功能,在各种后台管理里权限控制更是重中之重.在spring boot中使用 spring security 构建权限系统是非常轻松和简单的.下面我们就来快速入门 spring security .在开始前我们需要一对多关系的用户角色类,一个restful的controller.
- 添加 spring security 依赖
首先我默认大家都已经了解 spring boot 了,在 spring boot 项目中添加依赖是非常简单的.把对应的spring-boot-starter-*** 加到pom.xml文件中就行了
<dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-security</artifactid> </dependency>
- 配置 spring security
简单的使用 spring security 只要配置三个类就完成了,分别是:
userdetails
这个接口中规定了用户的几个必须要有的方法
public interface userdetails extends serializable { //返回分配给用户的角色列表 collection<? extends grantedauthority> getauthorities(); //返回密码 string getpassword(); //返回帐号 string getusername(); // 账户是否未过期 boolean isaccountnonexpired(); // 账户是否未锁定 boolean isaccountnonlocked(); // 密码是否未过期 boolean iscredentialsnonexpired(); // 账户是否激活 boolean isenabled(); }
userdetailsservice
这个接口只有一个方法 loaduserbyusername,是提供一种用 用户名 查询用户并返回的方法。
public interface userdetailsservice { userdetails loaduserbyusername(string var1) throws usernamenotfoundexception; }
websecurityconfigureradapter
这个内容很多,就不贴代码了,大家可以自己去看.
我们创建三个类分别继承上述三个接口
此 user 类不是我们的数据库里的用户类,是用来安全服务的.
/** * created by yuicon on 2017/5/14. */ public class user implements userdetails { private final string id; //帐号,这里是我数据库里的字段 private final string account; //密码 private final string password; //角色集合 private final collection<? extends grantedauthority> authorities; user(string id, string account, string password, collection<? extends grantedauthority> authorities) { this.id = id; this.account = account; this.password = password; this.authorities = authorities; } //返回分配给用户的角色列表 @override public collection<? extends grantedauthority> getauthorities() { return authorities; } @jsonignore public string getid() { return id; } @jsonignore @override public string getpassword() { return password; } //虽然我数据库里的字段是 `account` ,这里还是要写成 `getusername()`,因为是继承的接口 @override public string getusername() { return account; } // 账户是否未过期 @jsonignore @override public boolean isaccountnonexpired() { return true; } // 账户是否未锁定 @jsonignore @override public boolean isaccountnonlocked() { return true; } // 密码是否未过期 @jsonignore @override public boolean iscredentialsnonexpired() { return true; } // 账户是否激活 @jsonignore @override public boolean isenabled() { return true; } }
继承 userdetailsservice
/** * created by yuicon on 2017/5/14. */ @service public class userdetailsserviceimpl implements userdetailsservice { // jpa @autowired private userrepository userrepository; /** * 提供一种从用户名可以查到用户并返回的方法 * @param account 帐号 * @return userdetails * @throws usernamenotfoundexception */ @override public userdetails loaduserbyusername(string account) throws usernamenotfoundexception { // 这里是数据库里的用户类 user user = userrepository.findbyaccount(account); if (user == null) { throw new usernamenotfoundexception(string.format("没有该用户 '%s'.", account)); } else { //这里返回上面继承了 userdetails 接口的用户类,为了简单我们写个工厂类 return userfactory.create(user); } } }
userdetails 工厂类
/** * created by yuicon on 2017/5/14. */ final class userfactory { private userfactory() { } static user create(user user) { return new user( user.getid(), user.getaccount(), user.getpassword(), maptograntedauthorities(user.getroles().stream().map(role::getname).collect(collectors.tolist())) ); } //将与用户类一对多的角色类的名称集合转换为 grantedauthority 集合 private static list<grantedauthority> maptograntedauthorities(list<string> authorities) { return authorities.stream() .map(simplegrantedauthority::new) .collect(collectors.tolist()); } }
重点, 继承 websecurityconfigureradapter 类
/** * created by yuicon on 2017/5/14. */ @configuration @enablewebsecurity @enableglobalmethodsecurity(prepostenabled = true) public class websecurityconfig extends websecurityconfigureradapter { // spring会自动寻找实现接口的类注入,会找到我们的 userdetailsserviceimpl 类 @autowired private userdetailsservice userdetailsservice; @autowired public void configureauthentication(authenticationmanagerbuilder authenticationmanagerbuilder) throws exception { authenticationmanagerbuilder // 设置userdetailsservice .userdetailsservice(this.userdetailsservice) // 使用bcrypt进行密码的hash .passwordencoder(passwordencoder()); } // 装载bcrypt密码编码器 @bean public passwordencoder passwordencoder() { return new bcryptpasswordencoder(); } //允许跨域 @bean public webmvcconfigurer corsconfigurer() { return new webmvcconfigureradapter() { @override public void addcorsmappings(corsregistry registry) { registry.addmapping("/**").allowedorigins("*") .allowedmethods("get", "head", "post","put", "delete", "options") .allowcredentials(false).maxage(3600); } }; } @override protected void configure(httpsecurity httpsecurity) throws exception { httpsecurity // 取消csrf .csrf().disable() // 基于token,所以不需要session .sessionmanagement().sessioncreationpolicy(sessioncreationpolicy.stateless).and() .authorizerequests() .antmatchers(httpmethod.options, "/**").permitall() // 允许对于网站静态资源的无授权访问 .antmatchers( httpmethod.get, "/", "/*.html", "/favicon.ico", "/**/*.html", "/**/*.css", "/**/*.js", "/webjars/**", "/swagger-resources/**", "/*/api-docs" ).permitall() // 对于获取token的rest api要允许匿名访问 .antmatchers("/auth/**").permitall() // 除上面外的所有请求全部需要鉴权认证 .anyrequest().authenticated(); // 禁用缓存 httpsecurity.headers().cachecontrol(); } }
- 控制权限到 controller
使用 @preauthorize("hasrole('admin')") 注解就可以了
/** * 在 @preauthorize 中我们可以利用内建的 spel 表达式:比如 'hasrole()' 来决定哪些用户有权访问。 * 需注意的一点是 hasrole 表达式认为每个角色名字前都有一个前缀 'role_'。所以这里的 'admin' 其实在 * 数据库中存储的是 'role_admin' 。这个 @preauthorize 可以修饰controller也可修饰controller中的方法。 **/ @restcontroller @requestmapping("/users") @preauthorize("hasrole('user')") //有role_user权限的用户可以访问 public class usercontroller { @autowired private userrepository repository; @preauthorize("hasrole('admin')")//有role_admin权限的用户可以访问 @requestmapping(method = requestmethod.get) public list<user> getusers() { return repository.findall(); } }
- 结语
spring boot中 spring security 的入门非常简单,很快我们就能有一个满足大部分需求的权限系统了.而配合 spring security 的好搭档就是 jwt 了,两者的集成文章网络上也很多,大家可以自行集成.因为篇幅原因有不少代码省略了,需要的可以参考项目代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
下一篇: java实现表格tr拖动的实例(分享)