spring boot结合 security实现角色权限控制问题?

在springboot中集成spring security,实现不同角色的权限控制,有以下几个问题,希望帮忙解答一下,感激不尽,很久都没有解决。

问题1:登录处理url报403错误(因为权限问题无法访问),按照之前提过的问题,将http.csrf().disable()之后,登录url是可以访问了,但我不想这样做。有什么办法吗?

问题2:自定义UserDetailService中的loadUserByUsername,没有获取到前台的值(前台传的参数是account和pwd),如果改成参数改成username和pwd,就可以获取到前台的值。

问题3:真正的登录验证函数没有被执行到(没有返回相应数据),只执行了loadUserByUsername,没有执行@RequestMapping("login")映射的方法。

我不知道是不是我的思路有问题,是不是在spring security中,执行了loadUserByUsername,就不会执行自己的验证函数了?:@RequestMapping("login"),感觉应该不是这样。

以下是spring boot集成security的主要代码(也是在网上参考的资料):
主要参考:http://blog.csdn.net/u0127025...

WebSecurity

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    UserDetailsService customUserService() { //注册UserDetailsService 的bean
        return new CustomUserService();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.headers().frameOptions().disable().and()       //允许嵌入iframe
                .csrf().disable()
                .authorizeRequests()
                .antMatchers("/css/**", "/js/**","/images/**", "**/favicon.ico", "/lib/**").permitAll()
                .antMatchers("/admin/**").hasRole(SysConfig.ROLE_ADMIN)
                .anyRequest().authenticated().and()
                //.rememberMe().tokenValiditySeconds(60 * 60 * 24 * 7).key("").and()
                .formLogin().loginProcessingUrl("/user/login").loginPage("/login.html").permitAll().and()
                .logout().permitAll();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(customUserService());
    }
}

CustomUserService

@Service
public class CustomUserService implements UserDetailsService {

    @Autowired
    private UserService userService;

    @Override
    public UserDetails loadUserByUsername(String account) throws UsernameNotFoundException {
        System.out.println("loadUser " + account);
        User user = userService.getUserByAccount(account);
        if (user == null || user.isHasDel()) {
            throw new UsernameNotFoundException("user not exist or has been deleted");
        }
        List<GrantedAuthority> auths = new ArrayList<>();
        for (Role role : user.getRoles()) {
            auths.add(new SimpleGrantedAuthority(role.getName())); //不同用户会返回不同的role.name:USER, ADMIN
        }
        return new org.springframework.security.core.userdetails.User(account, user.getPwd(), auths);
    }
}

UserController中的login

    @PostMapping("login")
    public TMessage login(String account, String pwd) {
        if (StringUtil.isEmpty(account) || StringUtil.isEmpty(pwd) || !account.contains("@"))
            return new TMessage(TMessage.CODE_FAILURE, "用户名密码为空或格式不正确");
        if (userService.login(account, pwd))
            return new TMessage(TMessage.CODE_SUCCESS, "登录成功");
        else
            return new TMessage(TMessage.CODE_FAILURE, "登录失败,请检查用户名和密码");
    }

如果前台是这样的格式

username: a@b,
pwd: aaabbb

customservice中才能接收到username,其他参数接受不到,我想指定参数名是account,并且进入自己的处理函数(根据用户名和密码)

clipboard.png

阅读 6.6k
3 个回答

问题一:
默认Spring Security对CSRF攻击进行了防范,该项配置默认为开的状态,它会在页面到服务端请求过程中通过一个token来进行请求安全校验,如果前端使用jsp来渲染,那么需要在表单增加一个隐藏域来解决:

<!-- 开启防止CSRF攻击 -->
<input type="hidden" name="${_csrf.parameterName }" value="${_csrf.token}" />

如果使用thymeleaf2.1+模板或者使用了Spring MVC <form:form> 标签,那么CsrfToken这个值会被自动加入进去

If you are using Spring MVC <form:form> tag or Thymeleaf 2.1+ and are using @EnableWebSecurity, the CsrfToken is automatically included for you (using the CsrfRequestDataValueProcessor).

如果你使用的是ajax json请求,这时候就不能使用Http Paramaters来传入这个token,这时候 你可以通过head来提交这个token,代码如下:

<head>
    <meta name="_csrf" content="${_csrf.token}"/>
    <!-- default header name is X-CSRF-TOKEN -->
    <meta name="_csrf_header" content="${_csrf.headerName}"/>
    <!-- ... -->
</head>

基于jquery的demo:

$(function () {
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
$(document).ajaxSend(function(e, xhr, options) {
    xhr.setRequestHeader(header, token);
});
});

问题二:
Spring Security允许我们进行自定义校验,即实现UserDetailService接口,无论你使用任何类型的数据库存储或者调用第三方接口,那么你需要做的是就是将其返回结果进行转换成Spring Security.User所需要的东西,在做转换的时候,我们可能会想到的是使用apache commons-beanutils做数据转换(只是帮助思考,底层不一定是用它来实现),所以在使用的时候,你想使用参数名 accout转换成spring security的username,这个只能要我们自己手动来转换了,因为即使Spring Security再智能,他也是按照一定的约定来进行转换,所以你转换失败也是正常的...

你可以重写方法

现在新推出了一个权限框架,叫jCasbin(https://github.com/casbin/jca...)。jCasbin采用了元模型的设计思想,支持多种经典的访问控制方案,如ACL、RBAC、ABAC,还支持对RESTful API的控制。现在已经支持Spring Boot、JFinal等Web框架了。需要中文文档的话,可以看这篇文章:https://blog.csdn.net/hsluoyc...,或者在百度搜索:jCasbin

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题