Spring Security4、使用JSON处理授权交互
授权操作概念就不说了,正在Spring Security中如果想用授权也比较简单。
只要在设置访问路径时设置一个角色,然后再在设置用户时也该用户设置对应的角色,这样用户就能访问指定路径了。
在授权操作中,主要操作有:给用户设置角色、给路径设置访问角色、没有权限时返回JSON字符串
一、给用户设置角色
我们在配置登录用户的账号时,就可以设置角色。我们这里设置2个账号,admin账号给 admin
和 guest
角色,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系列文章请 点击这里 查看。
这是代码 码云地址 。
注意注意!!!项目是使用分支的方式来提交每次测试的代码的,请根据章节来我切换分支。