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

  • 相关阅读:
    2017-2018-1 20155320加分项目——pwd的实现
    2017-2018-1 20155306 20155320 20155326《信息安全技术》实验三——数字证书应用
    2017-2018-1 20155320 《信息安全系统设计基础》第八周学习总结
    2017-2018-1 20155320第八周课堂实践总结+课下作业
    2017-2018-1 20155320 《信息安全系统设计基础》第七周学习总结
    2017-2018-1 20155320 20155326 实验二 固件程序设计
    2017-2018-1 20155320第六周课堂实践总结
    2017-2018-1 20155320缓冲区溢出漏洞实验
    2017-2018-1 20155320 《信息安全系统设计基础》第六周学习总结
    2017-2018-1 20155318 实验三 实时系统报告
  • 原文地址:https://www.cnblogs.com/lixingwu/p/13286391.html
Copyright © 2020-2023  润新知