Spring Security一些避坑指南


最近开始在项目上使用Security, 之前只是修改别人写好的,很多原理不明白。这次有幸自己搭建框架。期间是一言难尽。下面会说说一些常见的坑

关于登录验证流程的坑

Security 登录验证流程(不需要传入密码)

此处是一个流程理解问题,在security的登录过程中是采取以用户名为查询条件,重写UserDetailsService类中的loadUserByUsername(String username) 方法。
具体流程为我们的service通过继承重写此方法,以username为条件查询出userName对应的用户。
此处坑点:按照我们以往的逻辑,验证用户需要传入用户名和密码,然后查出匹配账号。然而security是先通过用户名查出用户实体,之后再通过内置的match方法比较数据库中的密码和传入的密码。(密码会通过BCryptPasswordEncoder类进行不对称加密,不用担心明文泄露)。

Security 登录成功获取用户信息(密码为NULL)

当我们在进行登录成功之后,会通过 authentication.getPrincipal()方法去获取用户信息并封装为Json返回给前台(前后端分离项目)。
此处坑点:当我们通过authentication.getPrincipal()去获取用户信息,处于安全考虑,虽然会返回password字段,但是默认字段里是null的。(不是代码问题),下图中的password为null;

Security 通过Json 返回数据

前后端项目主要是通过JSON进行数据交互,而我们在设置response时需要注意设置编码格式。不然Json返还给前台会造成乱码。
此处坑点 :不注意的话,会造成类似乱码

{
    "msg": "?????",
    "principal": {
        "password": null,
        "username": "user",
        "authorities": [
            {
                "authority": "admin"
            }
        ],
        "accountNonExpired": true,
        "accountNonLocked": true,
        "credentialsNonExpired": true,
        "enabled": true
    }
}

设置格式类似

                        Map<String, Object> map = new HashMap<>();
                        map.put("msg", "登录成功!");
                        map.put("principal", authentication.getPrincipal());
                        resp.setContentType("application/json;charset=utf-8");

Security 会拦截Swagger2的访问

前后端项目有时会引入Swagger2进行接口对接,但是当我们通过/swagger-ui.html去访问页面时候,security会拦截我们的请求,可能机灵的小伙伴们会在config中添加允许访问路径

.antMatchers("/swagger-ui.html").permitAll();

但是,要知道swagger的页面会发送多个请求去获取接口信息,只是放开访问接口,也仅仅是显示页面全白。

此处坑点 :我们需要在config中重写个方法才能重新访问swagger2的页面数据。具体如下

    /*
     * 解决Security访问Swagger2被拦截的问题;
     * */
    @Override
    public void configure(WebSecurity web) throws Exception {
        // allow Swagger URL to be accessed without authentication
        web.ignoring().antMatchers(
                "/swagger-ui.html",
                "/v2/api-docs", // swagger api json
                "/swagger-resources/configuration/ui", // 用来获取支持的动作
                "/swagger-resources", // 用来获取api-docs的URI
                "/swagger-resources/configuration/security", // 安全选项
                "/swagger-resources/**",
                "/webjars/**"


        );;

关于权限验证流程的坑

@PreAuthorize 不起作用,post访问404

首先我们得明白此注解用于Controller层,用于对访问的用户进行权限控制。

//类似于这样
@RestController
@RequestMapping("/role")
@PreAuthorize("hasAuthority('admin')")  // 指定角色权限才能操作方法
public class RoleController {

此处坑点 : 请注意我这写的是hasAuthority(‘admin’),意思是有admin权限的用户可以访问,
各位此处需要根据自己的需求选择是权限控制还是角色控制。但是得注意如此处我是权限控制是因为我简单的写了登录权限。此处的权限名必须和hasAuthority(‘admin’)对应上。

// An highlighted block @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        try {
            //查询账号是否存在
            UserEntity sysUser = queryUserByAccountId(username);
            if (sysUser == null) {
                return null;
            }
            //比较密码,注册时已经加密过
            String password = passwordEncoder.encode("123");
            List<SimpleGrantedAuthority> authorities = new ArrayList<>();
            //查询role角色
//            List<SysRole> list = roleMapper.findRoleByUserId(sysUser.getId());
//            for(SysRole role : list) {
//                authorities.add(new SimpleGrantedAuthority(role.getName()));
            authorities.add(new SimpleGrantedAuthority("admin"));
//            }
            //封装 SpringSecurity  需要的UserDetails 对象并返回
            UserDetails userDetails = new User(sysUser.getUsername(), password, authorities);
            return userDetails;
        } catch (Exception e) {
            e.printStackTrace();
            //返回null即表示认证失败
            return null;
        }

其次,当我们开启控制层访问时,需要在配置类中开启权限访问开关

/**
 * SpringSecurity配置类
 * @Author xiongjian
 * @CreateTime 2019/10/1 9:40
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)//这个注解是关键
public class SecurityConfig extends WebSecurityConfigurerAdapter {

关于角色和权限在security中的区别

在我们传统的模型中,角色和权限是属于包含关系的,既角色中有多个权限。但是在security中角色和权限被视为同一个对象
列举代码


    //添加权限,此处注意权限和角色是不同的表 但是在security 中视为同样的
    //此处添加权限
        authorities.add(“某某菜单的权限”));
    //此处添加的角色名为ROLE_开头
    authorities.add(“ROLE_admin”));
   //封装 SpringSecurity  需要的UserDetails 对象并返回.密码会自动进行匹配
   UserDetails userDetails = new User(sysUser.getUsername(), sysUser.getPassword(), authorities);

写到这,就得说明下,security中角色和权限可以视为一样的,而区分两者的方法很简单,角色我们在添加时需要加上前缀ROLE_

您学废了吗?
其他内容之后再补充
希望对您有所帮助!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值