栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

spring-security详解

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

spring-security详解

随便写一下,增删改查返回对应的字符
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/security")
public class OauthBase {

    @GetMapping("/add")
    public String add(){
        return "add";
    }

    @GetMapping("/update")
    public String update(){
        return "update";
    }

    @GetMapping("/get")
    public String get(){
        return "get";
    }

    @GetMapping("/del")
    public String del(){
        return "del";
    }
}
基础认证配置类
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.stereotype.Component;

@Component
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        
        auth.inMemoryAuthentication().withUser("mykt").password("mykt").authorities("/");
    }

    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        
        http.authorizeRequests().antMatchers("
    @Bean
    public static NoOpPasswordEncoder PasswordEncoder(){
        return (NoOpPasswordEncoder)NoOpPasswordEncoder.getInstance();
    }
}

输入对应的账号密码就可以访问对应的接口,这个非常简单。 From表单验证
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        
        //http.authorizeRequests().antMatchers("
        http.authorizeRequests().antMatchers("
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        
        auth.inMemoryAuthentication().withUser("mykt-admin").password("mykt-admin").authorities("add","update","get","del");
        auth.inMemoryAuthentication().withUser("mykt-add").password("mykt-add").authorities("add");
        auth.inMemoryAuthentication().withUser("mykt-update").password("mykt-update").authorities("update");
        auth.inMemoryAuthentication().withUser("mykt-get").password("mykt-get").authorities("get");
        auth.inMemoryAuthentication().withUser("mykt-del").password("mykt-del").authorities("del");
    }

    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        
        //http.authorizeRequests().antMatchers("
        //http.authorizeRequests().antMatchers("
        http.authorizeRequests().antMatchers("/add").hasAnyAuthority("add")
                .antMatchers("/get").hasAnyAuthority("get")
                .antMatchers("/update").hasAnyAuthority("update")
                .antMatchers("/del").hasAnyAuthority("del")
                //form验证
                .antMatchers("
    @Bean
    public static NoOpPasswordEncoder PasswordEncoder(){
        return (NoOpPasswordEncoder)NoOpPasswordEncoder.getInstance();
    }
}
创建了五个账号,mykt-admin、mykt-add 、mykt-update 、mykt-get 、mykt-del,那么从账号名称中就可以看出来这些账号对应的权限 mykt-add测试



mykt-admin测试




权限不足跳转页面
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;


@Configuration
public class WebServerAutoConfiguration {

    @Bean
    public ConfigurableServletWebServerFactory webServerFactroy(){
        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
        ErrorPage errorPage403 = new ErrorPage(HttpStatus.FORBIDDEN,"/error/403");
        ErrorPage errorPage404 = new ErrorPage(HttpStatus.NOT_FOUND,"/error/404");
        ErrorPage errorPage500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR,"/error/500");
        factory.addErrorPages(errorPage403,errorPage404,errorPage500);
        return  factory;
    }

}
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ErrorController {

    @RequestMapping("/error/403")
    public String error403(){
        return "你当前访问的接口权限不足";
    }

    @RequestMapping("/error/404")
    public String error404(){
        return "资源不可用";
    }
}



为了演示效果, 正常的环境应该是返回码值,由前端对码值进行错误逻辑判断跳转到对应错误页面 自定义登陆页面 创建页面将html文件放在resource文件下面



    
    登陆


自定义登陆页面

用户名称
用户密码
指定登陆请求
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;


@Controller
public class LoginController {

    @RequestMapping("/login")
    public String login(){
        return "login";
    }

}
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.stereotype.Component;

@Component
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        
        auth.inMemoryAuthentication().withUser("mykt-admin").password("mykt-admin").authorities("add","update","get","del");
        auth.inMemoryAuthentication().withUser("mykt-add").password("mykt-add").authorities("add");
        auth.inMemoryAuthentication().withUser("mykt-update").password("mykt-update").authorities("update");
        auth.inMemoryAuthentication().withUser("mykt-get").password("mykt-get").authorities("get");
        auth.inMemoryAuthentication().withUser("mykt-del").password("mykt-del").authorities("del");
    }

    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        
        //http.authorizeRequests().antMatchers("
        //http.authorizeRequests().antMatchers("
        http.authorizeRequests().antMatchers("/add").hasAnyAuthority("add")
                .antMatchers("/get").hasAnyAuthority("get")
                .antMatchers("/update").hasAnyAuthority("update")
                .antMatchers("/del").hasAnyAuthority("del")
                .antMatchers("/login").permitAll()
                //form验证
                .antMatchers("
    @Bean
    public static NoOpPasswordEncoder PasswordEncoder(){
        return (NoOpPasswordEncoder)NoOpPasswordEncoder.getInstance();
    }
}

这个地方写的时候出现过一个问题,一直报个错误
Hint: This may be the result of an unspecified view, due to default view name generation
后面百度终于查到,说是没加一个包,加了就可以了
		
            org.springframework.boot
            spring-boot-starter-thymeleaf
        
RBAC权限架构(多对多关联)


用户绑定角色,然后角色绑定权限,那么创建用户的时候,只要给用户选择对应的角色就赋予对应的权限,可以这样理解。

springsecurity整合RBAC权限架构 sql表

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for sys_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission` (
  `id` int(10) NOT NULL,
  `permName` varchar(50) DEFAULT NULL,
  `permTag` varchar(50) DEFAULT NULL,
  `url` varchar(255) DEFAULT NULL COMMENT '请求url',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_permission
-- ----------------------------
INSERT INTO `sys_permission` VALUES ('1', '查询用户', 'getUser', '/getUser');
INSERT INTO `sys_permission` VALUES ('2', '添加用户', 'addUser', '/addUser');
INSERT INTO `sys_permission` VALUES ('3', '修改用户', 'updateUser', '/updateUser');
INSERT INTO `sys_permission` VALUES ('4', '删除用户', 'delUser', '/delUser');

-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
  `id` int(10) NOT NULL,
  `roleName` varchar(50) DEFAULT NULL,
  `roleDesc` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES ('1', 'admin', '管理员');
INSERT INTO `sys_role` VALUES ('2', 'add_user', '添加管理员');

-- ----------------------------
-- Table structure for sys_role_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_permission`;
CREATE TABLE `sys_role_permission` (
  `role_id` int(10) DEFAULT NULL,
  `perm_id` int(10) DEFAULT NULL,
  KEY `FK_Reference_3` (`role_id`),
  KEY `FK_Reference_4` (`perm_id`),
  CONSTRAINT `FK_Reference_3` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`id`),
  CONSTRAINT `FK_Reference_4` FOREIGN KEY (`perm_id`) REFERENCES `sys_permission` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_role_permission
-- ----------------------------
INSERT INTO `sys_role_permission` VALUES ('1', '1');
INSERT INTO `sys_role_permission` VALUES ('1', '2');
INSERT INTO `sys_role_permission` VALUES ('1', '3');
INSERT INTO `sys_role_permission` VALUES ('1', '4');
INSERT INTO `sys_role_permission` VALUES ('2', '2');

-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
  `id` int(10) NOT NULL,
  `username` varchar(50) DEFAULT NULL,
  `realname` varchar(50) DEFAULT NULL,
  `password` varchar(50) DEFAULT NULL,
  `createDate` date DEFAULT NULL,
  `lastLoginTime` date DEFAULT NULL,
  `enabled` int(5) DEFAULT NULL,
  `accountNonExpired` int(5) DEFAULT NULL,
  `accountNonLocked` int(5) DEFAULT NULL,
  `credentialsNonExpired` int(5) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES ('1', 'mayikt_admin', '张三', '99743025dc21f56c63d0cb2dd34f06f5', '2018-11-13', '2018-11-13', '1', '1', '1', '1');
INSERT INTO `sys_user` VALUES ('2', 'mayikt_add', '小余', 'a5a6996f2e1953161522a93cbb5fb556', '2018-11-13', '2018-11-13', '1', '1', '1', '1');

-- ----------------------------
-- Table structure for sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (
  `user_id` int(10) DEFAULT NULL,
  `role_id` int(10) DEFAULT NULL,
  KEY `FK_Reference_1` (`user_id`),
  KEY `FK_Reference_2` (`role_id`),
  CONSTRAINT `FK_Reference_1` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`id`),
  CONSTRAINT `FK_Reference_2` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_user_role
-- ----------------------------
INSERT INTO `sys_user_role` VALUES ('1', '1');
INSERT INTO `sys_user_role` VALUES ('2', '2');

然后就是SpringBoot整合mybatis(略) 那么我们现在要做的就是把以前写死的账号、密码、url都要通过查询数据动态的拿到,那么这个就是我们接下来要做的事情。 SecurityConfig
import com.my.mapper.PermissionMapper;
import com.my.model.PermissionModel;
import com.my.service.serviceimpl.MemberDetailsServiceimpl;
import com.my.utils.MD5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private PermissionMapper permissionMapper;

    @Autowired
    private MemberDetailsServiceimpl memberDetailsServiceimpl;

    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(memberDetailsServiceimpl).passwordEncoder(new PasswordEncoder() {
            
            @Override
            public String encode(CharSequence charSequence) {
                String encode = MD5Util.encode((String) charSequence);
                return encode;
            }
            
            @Override
            public boolean matches(CharSequence charSequence, String password) {
                //输入的密码进行加密
                String rawPass = MD5Util.encode((String) charSequence);
                //对比密码
                return  password.equals(rawPass);
            }
        });
    }

    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry authorizeRequests = http.authorizeRequests();
        //查询到所有的权限
        
        List permissionList = permissionMapper.getPermissionList();
        permissionList.forEach(x->{
            //添加规则
            authorizeRequests.antMatchers(x.getUrl()).hasAnyAuthority(x.getPermTag());
        });
        authorizeRequests
        .antMatchers("/login").permitAll()
        .antMatchers("
    @Bean
    public static NoOpPasswordEncoder PasswordEncoder(){
        return (NoOpPasswordEncoder)NoOpPasswordEncoder.getInstance();
    }
}
重写UserDetailsService.loadUserByUsername方法
import com.my.mapper.PermissionMapper;
import com.my.mapper.UserMapper;
import com.my.model.PermissionModel;
import com.my.model.UserModel;
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.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;


@Component
public class MemberDetailsServiceimpl implements UserDetailsService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private PermissionMapper permissionMapper;

    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        //根据登陆的userName查询这个用户
        
        UserModel user = userMapper.getUser(userName);
        if(user == null){
            return null;
        }
        //根据用户查询权限
        
        List permissionList = permissionMapper.getPermission(user.getUsername());
        //创建权限集合
        List grantedAuthorities = new ArrayList<>();
        //添加权限
        permissionList.forEach(x ->{
            grantedAuthorities.add(new SimpleGrantedAuthority(x.getPermTag()));
        });
        //将权限绑定到user
        user.setAuthorities(grantedAuthorities);
        return user;
    }
}
UserModel 这个地方要注意,这个User实体类实现了UserDetails重写了方法,那么这些方法默认是返回false,我们要改成true,不然登陆会出现失败的情况。还有一个问题,就是重写UserDetails的方法,刚好我们字段也有一个类似的字段,在启动的时候项目就检查到这个不符合规范,最后我也是将我实体类中的字段set get方法删除。
public class UserModel implements UserDetails {
    private Integer id;
    private String username;
    private String realname;
    private String password;
    private Date createDate;
    private Date lastLoginTime;
    private Integer enabled;
    private Integer accountNonExpired;
    private Integer accountNonLocked;
    private Integer credentialsNonExpired;
	//用户跟权限板顶,一对多
    private List authorities = new ArrayList<>();

    @Override
    public List getAuthorities() {
        return authorities;
    }

    public void setAuthorities(List authorities) {
        this.authorities = authorities;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getRealname() {
        return realname;
    }

    public void setRealname(String realname) {
        this.realname = realname;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Date getCreateDate() {
        return createDate;
    }

    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }

    public Date getLastLoginTime() {
        return lastLoginTime;
    }

    public void setLastLoginTime(Date lastLoginTime) {
        this.lastLoginTime = lastLoginTime;
    }

}
MD5加密password
import java.security.MessageDigest;

public class MD5Util {
    //盐
    private static final String SALT = "mayikt";

    public static String encode(String password) {
        password = password + SALT;
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        char[] charArray = password.toCharArray();
        byte[] byteArray = new byte[charArray.length];

        for (int i = 0; i < charArray.length; i++)
            byteArray[i] = (byte) charArray[i];
        byte[] md5Bytes = md5.digest(byteArray);
        StringBuffer hexValue = new StringBuffer();
        for (int i = 0; i < md5Bytes.length; i++) {
            int val = ((int) md5Bytes[i]) & 0xff;
            if (val < 16) {
                hexValue.append("0");
            }

            hexValue.append(Integer.toHexString(val));
        }
        return hexValue.toString();
    }
}
演示admin账户,全部权限。我只写了一个查询,其他省略了。



演示mykt-add,这个账户只有add权限,那么我们去用这个账户登陆去查询看看



最后我将代码上传到百度网盘

链接:https://pan.baidu.com/s/1ImSsNg1XdMlZEU922jEiKA
提取码:yyds

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/946266.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号