当前位置: 代码网 > it编程>编程语言>Java > Spring Security注解方式权限控制过程

Spring Security注解方式权限控制过程

2025年03月12日 Java 我要评论
一、摘要spring security除了可以在配置文件中配置权限校验规则,还可以使用注解方式控制类 中方法的调用。例如controller中的某个方法要求必须具有某个权限才可以访问,此时就 可以使用

一、摘要

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页面

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com