HttpSecurity 权限配置
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(authorize -> {
authorize
// 放行请求:针对含有 admin 权限的用户放行 /user/get 接口
.requestMatchers("/users/get").hasAuthority("admin")
// 放行请求:针对含有 tourist 权限的用户放行 /get 接口
.requestMatchers("/test/auth").hasAuthority("tourist")
// 放行请求:针对 ROLE_admin 角色,放行/users/list 接口
.requestMatchers("/users/list").hasRole("ROLE_admin")
// 对所有用户放行
.requestMatchers("/login", "/test/**").permitAll()
// 所有的请求都需要授权保护,不授权保护的请求要写在anyRequest之前
.anyRequest()
// 以认证的会自动授权
.authenticated();
});
http.exceptionHandling(exc -> {
// 用户未认证
exc.authenticationEntryPoint(new MyAuthenticationSuccessHandler());
// 请求被拒绝
exc.accessDeniedHandler(new MyAuthenticationSuccessHandler());
}
);
// 开启跨域请求
http.cors(withDefaults());
return http.build();
}
在 loadUserByUsername 方法,在查询数据库用户信息的时候,同时查询出用户的权限,这里以角色名代指权限
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
log.info("username:" + username);
// 用户名称不唯一,这里的账号名account,不是用户名
// 这里user实现了Security的UserDetails对象
UsersDO user = usersMapper.selectByAccount(username);
if (user == null || StringUtils.isEmpty(user.getPassword())) {
throw new UsernameNotFoundException(username + ":用户不存在");
}
// 获取用户角色列表
List<RoleDO> list = usersMapper.selectByAccountRole(username);
user.setList(list);
return user;
}
获取用户信息
@Mapper
public interface UsersMapper extends BaseMapper<Users> {
/**
* 分页查询
*/
List<ResUsers> listByPage(Page<ResUsers> page, @Param("param") ReqUsersQuery req);
@Select("select ID,ACCOUNT ,USERNAME,PASSWORD ,SEX ,AGE ,PHONE_NUMBER ,DEPARTMENT_NO,DELETED from tm_user where ACCOUNT =#{account}")
UsersDO selectByAccount(@Param("account") String account);
@Select("select t1.ACCOUNT ,t2.role_name from tm_user t1 left join tm_user_role t2 on t1.ACCOUNT =t2.account \n" +
"left join tm_role t3 on t2.role_name =t3.role_name where t1.ACCOUNT =#{account}")
List<RoleDO> selectByAccountRole(@Param("account") String username);
}
实体类:
@Data
@Slf4j
@TableName("tm_user")
// 实现了Security的UserDetails对象
public class UsersDO implements UserDetails {
/**
* 账号
*/
private String id;
/**
* 账号
*/
private String account;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 逻辑删除
*/
@TableLogic
@TableField(value = "DELETED", fill = FieldFill.INSERT, jdbcType = JdbcType.VARCHAR)
private String deleted;
/**
* 用户角色列表
*/
private List<RoleDO> list;
/**
* 权限列表
*/
private Set<GrantedAuthority> authorities =new HashSet<>();
@Override
public boolean isEnabled() {
// 通过逻辑删除字段判断是否启用
return Integer.valueOf(this.getDeleted()) == 0 ? true : false;
}
@Override
public boolean isAccountNonExpired() {
//用户是否未过期
return true;
}
@Override
public boolean isCredentialsNonExpired() {
// 用户凭证是否未过期
return true;
}
@Override
public boolean isAccountNonLocked() {
// 用户是否没有被锁定
return true;
}
/**
* 获取权限列表,暂时以角色名代表权限
* @return
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
// 权限列表
for (RoleDO roleDO : list){
authorities.add(()->roleDO.getRoleName());
}
return authorities;
}
/**
* 设置角色 , 这里参考了 Security 的源码
* @param roles
*/
public void roles(String... roles) {
for (String role : roles) {
// 这里要加上前缀 “ROLE_”
Assert.isTrue(!role.startsWith("ROLE_"),
() -> role + " cannot start with ROLE_ (it is automatically added)");
authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
}
}
}
用户登录后,如果没有对应权限,默认会抛出403异常
HttpSecurity 权限配置
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(authorize -> {
authorize
// 放行请求:针对含有 admin 权限的用户放行 /user/get 接口
.requestMatchers("/users/get").hasAuthority("admin")
// 放行请求:针对含有 tourist 权限的用户放行 /get 接口
.requestMatchers("/test/auth").hasAuthority("tourist")
// 放行请求:针对 ROLE_admin 角色,放行/users/list 接口
.requestMatchers("/users/list").hasRole("ROLE_admin")
// 对所有用户放行
.requestMatchers("/login", "/test/**").permitAll()
// 所有的请求都需要授权保护,不授权保护的请求要写在anyRequest之前
.anyRequest()
// 以认证的会自动授权
.authenticated();
});
http.exceptionHandling(exc -> {
// 用户未认证
exc.authenticationEntryPoint(new MyAuthenticationSuccessHandler());
// 请求被拒绝
exc.accessDeniedHandler(new MyAuthenticationSuccessHandler());
}
);
// 开启跨域请求
http.cors(withDefaults());
return http.build();
}
在 loadUserByUsername 方法,在查询数据库用户信息的时候,同时查询出用户的权限,这里以角色名代指权限
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
log.info("username:" + username);
// 用户名称不唯一,这里的账号名account,不是用户名
// 这里user实现了Security的UserDetails对象
UsersDO user = usersMapper.selectByAccount(username);
if (user == null || StringUtils.isEmpty(user.getPassword())) {
throw new UsernameNotFoundException(username + ":用户不存在");
}
// 获取用户角色列表
List<RoleDO> list = usersMapper.selectByAccountRole(username);
user.setList(list);
return user;
}
获取用户信息
@Mapper
public interface UsersMapper extends BaseMapper<Users> {
/**
* 分页查询
*/
List<ResUsers> listByPage(Page<ResUsers> page, @Param("param") ReqUsersQuery req);
@Select("select ID,ACCOUNT ,USERNAME,PASSWORD ,SEX ,AGE ,PHONE_NUMBER ,DEPARTMENT_NO,DELETED from tm_user where ACCOUNT =#{account}")
UsersDO selectByAccount(@Param("account") String account);
@Select("select t1.ACCOUNT ,t2.role_name from tm_user t1 left join tm_user_role t2 on t1.ACCOUNT =t2.account \n" +
"left join tm_role t3 on t2.role_name =t3.role_name where t1.ACCOUNT =#{account}")
List<RoleDO> selectByAccountRole(@Param("account") String username);
}
实体类:
@Data
@Slf4j
@TableName("tm_user")
// 实现了Security的UserDetails对象
public class UsersDO implements UserDetails {
/**
* 账号
*/
private String id;
/**
* 账号
*/
private String account;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 逻辑删除
*/
@TableLogic
@TableField(value = "DELETED", fill = FieldFill.INSERT, jdbcType = JdbcType.VARCHAR)
private String deleted;
/**
* 用户角色列表
*/
private List<RoleDO> list;
/**
* 权限列表
*/
private Set<GrantedAuthority> authorities =new HashSet<>();
@Override
public boolean isEnabled() {
// 通过逻辑删除字段判断是否启用
return Integer.valueOf(this.getDeleted()) == 0 ? true : false;
}
@Override
public boolean isAccountNonExpired() {
//用户是否未过期
return true;
}
@Override
public boolean isCredentialsNonExpired() {
// 用户凭证是否未过期
return true;
}
@Override
public boolean isAccountNonLocked() {
// 用户是否没有被锁定
return true;
}
/**
* 获取权限列表,暂时以角色名代表权限
* @return
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
// 权限列表
for (RoleDO roleDO : list){
authorities.add(()->roleDO.getRoleName());
}
return authorities;
}
/**
* 设置角色 , 这里参考了 Security 的源码
* @param roles
*/
public void roles(String... roles) {
for (String role : roles) {
// 这里要加上前缀 “ROLE_”
Assert.isTrue(!role.startsWith("ROLE_"),
() -> role + " cannot start with ROLE_ (it is automatically added)");
authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
}
}
}
用户登录后,如果没有对应权限,默认会抛出403异常
HttpSecurity 权限配置
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(authorize -> {
authorize
// 放行请求:针对含有 admin 权限的用户放行 /user/get 接口
.requestMatchers("/users/get").hasAuthority("admin")
// 放行请求:针对含有 tourist 权限的用户放行 /get 接口
.requestMatchers("/test/auth").hasAuthority("tourist")
// 放行请求:针对 ROLE_admin 角色,放行/users/list 接口
.requestMatchers("/users/list").hasRole("ROLE_admin")
// 对所有用户放行
.requestMatchers("/login", "/test/**").permitAll()
// 所有的请求都需要授权保护,不授权保护的请求要写在anyRequest之前
.anyRequest()
// 以认证的会自动授权
.authenticated();
});
http.exceptionHandling(exc -> {
// 用户未认证
exc.authenticationEntryPoint(new MyAuthenticationSuccessHandler());
// 请求被拒绝
exc.accessDeniedHandler(new MyAuthenticationSuccessHandler());
}
);
// 开启跨域请求
http.cors(withDefaults());
return http.build();
}
在 loadUserByUsername 方法,在查询数据库用户信息的时候,同时查询出用户的权限,这里以角色名代指权限
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
log.info("username:" + username);
// 用户名称不唯一,这里的账号名account,不是用户名
// 这里user实现了Security的UserDetails对象
UsersDO user = usersMapper.selectByAccount(username);
if (user == null || StringUtils.isEmpty(user.getPassword())) {
throw new UsernameNotFoundException(username + ":用户不存在");
}
// 获取用户角色列表
List<RoleDO> list = usersMapper.selectByAccountRole(username);
user.setList(list);
return user;
}
获取用户信息
@Mapper
public interface UsersMapper extends BaseMapper<Users> {
/**
* 分页查询
*/
List<ResUsers> listByPage(Page<ResUsers> page, @Param("param") ReqUsersQuery req);
@Select("select ID,ACCOUNT ,USERNAME,PASSWORD ,SEX ,AGE ,PHONE_NUMBER ,DEPARTMENT_NO,DELETED from tm_user where ACCOUNT =#{account}")
UsersDO selectByAccount(@Param("account") String account);
@Select("select t1.ACCOUNT ,t2.role_name from tm_user t1 left join tm_user_role t2 on t1.ACCOUNT =t2.account \n" +
"left join tm_role t3 on t2.role_name =t3.role_name where t1.ACCOUNT =#{account}")
List<RoleDO> selectByAccountRole(@Param("account") String username);
}
实体类:
@Data
@Slf4j
@TableName("tm_user")
// 实现了Security的UserDetails对象
public class UsersDO implements UserDetails {
/**
* 账号
*/
private String id;
/**
* 账号
*/
private String account;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 逻辑删除
*/
@TableLogic
@TableField(value = "DELETED", fill = FieldFill.INSERT, jdbcType = JdbcType.VARCHAR)
private String deleted;
/**
* 用户角色列表
*/
private List<RoleDO> list;
/**
* 权限列表
*/
private Set<GrantedAuthority> authorities =new HashSet<>();
@Override
public boolean isEnabled() {
// 通过逻辑删除字段判断是否启用
return Integer.valueOf(this.getDeleted()) == 0 ? true : false;
}
@Override
public boolean isAccountNonExpired() {
//用户是否未过期
return true;
}
@Override
public boolean isCredentialsNonExpired() {
// 用户凭证是否未过期
return true;
}
@Override
public boolean isAccountNonLocked() {
// 用户是否没有被锁定
return true;
}
/**
* 获取权限列表,暂时以角色名代表权限
* @return
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
// 权限列表
for (RoleDO roleDO : list){
authorities.add(()->roleDO.getRoleName());
}
return authorities;
}
/**
* 设置角色 , 这里参考了 Security 的源码
* @param roles
*/
public void roles(String... roles) {
for (String role : roles) {
// 这里要加上前缀 “ROLE_”
Assert.isTrue(!role.startsWith("ROLE_"),
() -> role + " cannot start with ROLE_ (it is automatically added)");
authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
}
}
}
用户登录后,如果没有对应权限,默认会抛出403异常
可以自定义请求被拒绝的返回结果:
@Configuration
@Slf4j
public class MyAuthenticationSuccessHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
log.info("请求被拒绝-------------->");
response.setContentType("application/json;charset=UTF-8");
Map<String, Object> res = new HashMap<>();
res.put("code", "-1");
res.put("message", "请求被拒绝");
Map<String, Object> data = new HashMap<>();
res.put("data", data);
response.getWriter().println(JSONUtil.toJsonStr(res));
}
}
权限模型
通过 RBAC 获取到用户的具体权限后,再通过 Security 的 用户-权限-资源 来进行权限控制
// 针对某个资源,对某个权限来放行
.requestMatchers("/users/get").hasAuthority("function_id")
使用注解,针对某个方法开启授权保护
开启配置:
@Configuration
// 开启spring Security的自定义配置,在springBoot项目中可以省略此注解,因为Security-stater默认开启了自定义配置
@EnableWebSecurity
// 开启基于方法的授权
@EnableMethodSecurity
public class SecurityConfig {
}
给方法增加权限保护
@PreAuthorize("hasRole('admin')")
@GetMapping("/apply")
public BaseResultModel apply(){
return BaseResultModel.success("授权返回成功");
}
注解及含义
授权的原理分析