一、摘要
spring security除了可以在配置文件中配置权限校验规则,还可以使用注解方式控制类 中方法的调用。
例如controller中的某个方法要求必须具有某个权限才可以访问,此时就 可以使用spring security框架提供的注解方式进行控制。
二、实现步骤
2.1 在配置类中添加权限注解的支持
package com.by.config; //import com.by.service.userservice; import com.by.service.userservice; import org.springframework.beans.factory.annotation.autowired; import org.springframework.context.annotation.bean; import org.springframework.context.annotation.configuration; import org.springframework.security.config.annotation.authentication.builders.authenticationmanagerbuilder; import org.springframework.security.config.annotation.method.configuration.enableglobalmethodsecurity; import org.springframework.security.config.annotation.web.builders.httpsecurity; import org.springframework.security.config.annotation.web.builders.websecurity; import org.springframework.security.config.annotation.web.configuration.websecurityconfigureradapter; import org.springframework.security.crypto.bcrypt.bcryptpasswordencoder; import org.springframework.security.crypto.password.passwordencoder; /** * spring security 核心配置 */ @configuration @enableglobalmethodsecurity(prepostenabled = true)//开启权限注解支持 public class websecurityconfig extends websecurityconfigureradapter { @autowired private userservice userservice; @autowired private passwordencoder passwordencoder; /** * 配置认证信息的来源 * authenticationmanagerbuilder认证管理器 */ @override protected void configure(authenticationmanagerbuilder auth) throws exception { // 配置认证提供者 auth.userdetailsservice(userservice).passwordencoder(passwordencoder);//配置认证提供者 super.configure(auth);//密码 } /** * 配置web的安全(忽略的静态资源) * * @param web * @throws exception */ @override public void configure(websecurity web) throws exception { //web.ignoring().antmatchers("/pages/a.html","/pages/b.html"); //web.ignoring().antmatchers("/pages/**"); //指定login.html页面可以匿名访问 web.ignoring().antmatchers("/login.html"); } /** * 配置http请求的安全(认证、授权、退出) * httpsecurity 用于构建一个安全过滤器链 securityfilterchain * * @param http * @throws exception */ @override protected void configure(httpsecurity http) throws exception { // super.configure(http); http.formlogin() .loginpage("/login.html")// 默认页面 .loginprocessingurl("/login")//请求 .usernameparameter("username") .passwordparameter("password") // 请求成功后访问哪个路径 .defaultsuccessurl("/index.html",true); //权限配置 http.authorizerequests() //.antmatchers("pages/a.html").authenticated() .antmatchers("/pages/b.html").hasauthority("add") /** * 拥有role_admin可以访问d页面 * 注意:此处虽然写的是admin,但是框架会自动添加前缀role_ */ .antmatchers("pages/c.html").hasrole("admin") // 其他资源均需要登录后访问 .anyrequest().authenticated(); // super.configure(http); //关闭跨站请求防护 http.csrf().disable(); } /** * 配置加密对象 * @return */ @bean public passwordencoder passwordencoder(){ return new bcryptpasswordencoder(); } }
2.2 创建controller类
在controller的方法上加入注解进行权限控制
package com.by.controller; import org.springframework.security.access.prepost.preauthorize; import org.springframework.web.bind.annotation.requestmapping; import org.springframework.web.bind.annotation.restcontroller; @restcontroller @requestmapping("/hello") public class hellocontroller { @requestmapping("/add") /** * 表示用户要拥有add权限 才能访问该方法 */ @preauthorize("hasauthority('add')") public string add(){ system.out.println("add"); return "success"; } }
2.3 userservice类
package com.by.service; import com.by.pojo.userinfo; import org.springframework.beans.factory.annotation.autowired; import org.springframework.security.core.grantedauthority; import org.springframework.security.core.authority.simplegrantedauthority; import org.springframework.security.core.userdetails.user; import org.springframework.security.core.userdetails.userdetails; import org.springframework.security.core.userdetails.userdetailsservice; import org.springframework.security.core.userdetails.usernamenotfoundexception; import org.springframework.security.crypto.bcrypt.bcryptpasswordencoder; import org.springframework.security.crypto.password.passwordencoder; import org.springframework.stereotype.component; import java.util.arraylist; import java.util.hashmap; import java.util.list; import java.util.map; @component public class userservice implements userdetailsservice { @autowired private passwordencoder passwordencoder; //模拟向数据库中插入数据 public map<string, userinfo> map = new hashmap<>(); public void init() { userinfo u1 = new userinfo(); u1.setusername("admin"); u1.setpassword(passwordencoder.encode("123")); userinfo u2 = new userinfo(); u2.setusername("user"); u2.setpassword(passwordencoder.encode("123")); map.put(u1.getusername(), u1); map.put(u2.getusername(), u2); } @override public userdetails loaduserbyusername(string username) throws usernamenotfoundexception { init(); system.out.println("username:" + username); //模拟从数据库中查询用户 userinfo userinfo = map.get(username); if (userinfo == null) { return null; } //模拟查询数据库中用户的密码 去掉明文标识{noop} string password = userinfo.getpassword(); list<grantedauthority> list = new arraylist<>(); //授权,后期需要改为查询数据库动态获得用户拥有的权限和角色 if (username.equals("admin")) { list.add(new simplegrantedauthority("add")); list.add(new simplegrantedauthority("delete")); } list.add(new simplegrantedauthority("role_admin")); user user = new user(username, password, list); return user; } public static void main(string[] args) { for (int i = 0; i < 3; i++) { string password="123456"; /** * bcryptpasswordencoder是spring security * 提供的一个加密的api */ bcryptpasswordencoder bcryptpasswordencoder = new bcryptpasswordencoder(); string hashpassword = bcryptpasswordencoder.encode(password); system.out.println(hashpassword); boolean flag = bcryptpasswordencoder.matches("123456", hashpassword); system.out.println(flag); } } }
三、测试
可以看出admin有add方法的访问权限,而user则没有add方法的访问权限
3.1 user测试
3.2 admin 测试
四、退出登录功能
用户完成登录后spring security框架会记录当前用户认证状态为已认证状态,即表示用 户登录成功了。
那用户如何退出登录呢?我们可以配置类中进行如下 配置:
package com.by.config; //import com.by.service.userservice; import com.by.service.userservice; import org.springframework.beans.factory.annotation.autowired; import org.springframework.context.annotation.bean; import org.springframework.context.annotation.configuration; import org.springframework.security.config.annotation.authentication.builders.authenticationmanagerbuilder; import org.springframework.security.config.annotation.method.configuration.enableglobalmethodsecurity; import org.springframework.security.config.annotation.web.builders.httpsecurity; import org.springframework.security.config.annotation.web.builders.websecurity; import org.springframework.security.config.annotation.web.configuration.websecurityconfigureradapter; import org.springframework.security.crypto.bcrypt.bcryptpasswordencoder; import org.springframework.security.crypto.password.passwordencoder; /** * spring security 核心配置 */ @configuration @enableglobalmethodsecurity(prepostenabled = true)//开启权限注解支持 public class websecurityconfig extends websecurityconfigureradapter { @autowired private userservice userservice; @autowired private passwordencoder passwordencoder; /** * 配置认证信息的来源 * authenticationmanagerbuilder认证管理器 */ @override protected void configure(authenticationmanagerbuilder auth) throws exception { // 配置认证提供者 auth.userdetailsservice(userservice).passwordencoder(passwordencoder);//配置认证提供者 super.configure(auth);//密码 } /** * 配置web的安全(忽略的静态资源) * * @param web * @throws exception */ @override public void configure(websecurity web) throws exception { //web.ignoring().antmatchers("/pages/a.html","/pages/b.html"); //web.ignoring().antmatchers("/pages/**"); //指定login.html页面可以匿名访问 web.ignoring().antmatchers("/login.html"); } /** * 配置http请求的安全(认证、授权、退出) * httpsecurity 用于构建一个安全过滤器链 securityfilterchain * * @param http * @throws exception */ @override protected void configure(httpsecurity http) throws exception { // super.configure(http); http.formlogin() .loginpage("/login.html")// 默认页面 .loginprocessingurl("/login")//请求 .usernameparameter("username") .passwordparameter("password") // 请求成功后访问哪个路径 .defaultsuccessurl("/index.html",true); //权限配置 http.authorizerequests() //.antmatchers("pages/a.html").authenticated() .antmatchers("/pages/b.html").hasauthority("add") /** * 拥有role_admin可以访问d页面 * 注意:此处虽然写的是admin,但是框架会自动添加前缀role_ */ .antmatchers("pages/c.html").hasrole("admin") // 其他资源均需要登录后访问 .anyrequest().authenticated(); /** * 退出登录 */ http.logout() .logouturl("/logout") .logoutsuccessurl("/login.html").invalidatehttpsession(true); // super.configure(http); //关闭跨站请求防护 http.csrf().disable(); } /** * 配置加密对象 * @return */ @bean public passwordencoder passwordencoder(){ return new bcryptpasswordencoder(); } }
在a.html 设置一个退出登录的超链接
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>title</title> </head> <body> 我是b.html <a href="/logout" rel="external nofollow" >退出登录</a> </body> </html>
测试
登录后访问localhost:8083/pages/a.html 然后点击退出登录。
如果用户要退出登录,只需要请求/logout这个url地址就 可以,最后页面会跳转到login.html页面
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论