Spring Security4、使用JSON处理授权交互

授权操作概念就不说了,正在Spring Security中如果想用授权也比较简单。

只要在设置访问路径时设置一个角色,然后再在设置用户时也该用户设置对应的角色,这样用户就能访问指定路径了。

在授权操作中,主要操作有:给用户设置角色、给路径设置访问角色、没有权限时返回JSON字符串

一、给用户设置角色

我们在配置登录用户的账号时,就可以设置角色。我们这里设置2个账号,admin账号给 adminguest 角色,user账号给 guest 角色。多个账号我们可以用and链接起来,设置的其他和设置一个用于一模一样。

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication()
            .passwordEncoder(new BCryptPasswordEncoder())
        
            // admin账号给 admin 和 guest 角色
            .withUser("admin")
            .password(new BCryptPasswordEncoder().encode("123456"))
            .roles("admin", "guest")
        
            .and()
        
            // user账号给 guest 角色
            .withUser("user")
            .password(new BCryptPasswordEncoder().encode("000000"))
            .roles("guest");
}

二、给路径设置访问角色

我们在配置认证和授权的策略时,除了设置忽略的路径,我们也可以为指定的路径设置访问的角色。这样在访问路径时,就会判断当前登录的对象有没有对应的角色,没有就会重定向到 /error,有对应的角色就能正常访问。

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
        .antMatchers("/code", "/login", "/logout", "/doLogin").permitAll()

        // 给admin和guest开头的路径设置admin角色
        .antMatchers("/admin/**", "/guest/**").hasRole("admin")
        
        // 给guest开头的路径设置guest角色
        .antMatchers("/guest/**").hasRole("guest")

        // 其他路径登录以后就可以访问
        .anyRequest().authenticated()
        
        .and().formLogin()
        .usernameParameter("username")
        .passwordParameter("password")
        .loginProcessingUrl("/doLogin")
        .successHandler(successHandler)
        .failureHandler(failureHandler)
        .and().cors()
        .and().csrf().disable();
}

三、没有权限时返回JSON字符串

我们在登录时登录成功和登录失败都会有对应的处理程序,那么授权操作也应该有对应的处理程序。那我们这个处理程序要实现哪一个接口呢?看代码。

import cn.hutool.core.lang.Console;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.ContentType;
import cn.hutool.json.JSONUtil;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 没有权限访问
 *
 * @author lixingwu
 */
@Component
public class JsonAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(
            HttpServletRequest request, HttpServletResponse response,
            AccessDeniedException accessDeniedException
    ) throws IOException, ServletException {
        Console.log("没有权限访问,{}", accessDeniedException);
        Dict res = Dict.create()
                .set("code", 1002)
                .set("msg", "没有权限访问")
                .set("data", accessDeniedException.getMessage());
        ServletUtil.write(response, JSONUtil.toJsonStr(res), ContentType.JSON.toString(CharsetUtil.CHARSET_UTF_8));
    }
}

我们现在把我们写的 没有权限 处理程序配置到HttpSecurity上,这样访问没有权限的路径就返回我们设置的json字符串了。完整配置看代码。

import com.miaopasi.securitydemo.config.security.handler.JsonAccessDeniedHandler;
import com.miaopasi.securitydemo.config.security.handler.JsonFailureHandler;
import com.miaopasi.securitydemo.config.security.handler.JsonSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
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.bcrypt.BCryptPasswordEncoder;

/**
 * Security配置类,会覆盖yml配置文件的内容
 *
 * @author lixingwu
 */
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final JsonSuccessHandler successHandler;
    private final JsonFailureHandler failureHandler;
    private final JsonAccessDeniedHandler accessDeniedHandler;

    @Autowired
    public SecurityConfig(JsonSuccessHandler successHandler, JsonFailureHandler failureHandler, JsonAccessDeniedHandler accessDeniedHandler) {
        this.successHandler = successHandler;
        this.failureHandler = failureHandler;
        this.accessDeniedHandler = accessDeniedHandler;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/code", "/login", "/logout", "/doLogin").permitAll()
                .antMatchers("/admin/**", "/guest/**").hasRole("admin")
                .antMatchers("/guest/**").hasRole("guest")

                .anyRequest().authenticated()
                .and().formLogin()
                .usernameParameter("username")
                .passwordParameter("password")
                .loginProcessingUrl("/doLogin")
                .successHandler(successHandler)
                .failureHandler(failureHandler)

                // 设置没有权限访问的处理程序
                .and().exceptionHandling()
                .accessDeniedHandler(accessDeniedHandler)

                .and().cors()
                .and().csrf().disable();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .passwordEncoder(new BCryptPasswordEncoder())
                .withUser("admin")
                .password(new BCryptPasswordEncoder().encode("123456"))
                .roles("admin", "guest")
                .and()
                .withUser("user")
                .password(new BCryptPasswordEncoder().encode("000000"))
                .roles("guest");
    }
}

四、测试

在测试前我先创建一个测试的 TestController.java ,里面提供几个接口:

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

@GetMapping("/admin/get2")
public String adminGet2() {
    return "admin get2";
}

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

@GetMapping("/guest/get2")
public String guestGet2() {
    return "guest get2";
}

现在启动程序,进行以下操作:

(1)登录 admin 用户,访问 /admin/get/guest/get/admin/get2/guest/get2 接口正常访问。

(2)登录 user 用户,访问 /guest/get/guest/get2 正常,访问 /admin/get/admin/get2 ,返回 没有权限访问 JSON字符串。

{
    "msg": "没有权限访问",
    "code": 1002,
    "data": "Access is denied"
}

spring security系列文章请 点击这里 查看。
这是代码 码云地址
注意注意!!!项目是使用分支的方式来提交每次测试的代码的,请根据章节来我切换分支。

posted @ 2020-07-12 01:01  喵喵扑  阅读(567)  评论(0编辑  收藏  举报