Java动态分配角色权限_Spring boot security 动态角色权限

本文介绍了如何在Spring Boot项目中使用Spring Boot Security实现动态角色和权限的配置。通过创建多个类如MyPasswordEncoder、WebSecurityConfig、CustomUserService等,实现了用户密码加密、权限过滤、登录验证等功能。数据库设计包括用户、角色、权限和关联表,并提供了配置文件及部分关键代码示例。
摘要由CSDN通过智能技术生成

原来项目一直使用spring mvc用的一套动态权限角色控制,现在项目更换spring boot来开发,原来的权限控制不起作用,于是使用spring boot security来实现动态角色和权限的配置功能。现功能只是为了实现cms后台的控制,还没有去做接口的动态权限控制,如果下一步需要并实现了功能会分享出来。

spring boot 使用的是2.1.0.RELEASE版本,废话不多说上配置文件。

pom.xml

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

com.simmytech.cms

cms-platform

1.0.0-SNAPSHOT

war

cms-platform

http://maven.apache.org

org.springframework.boot

spring-boot-starter-parent

2.1.0.RELEASE

UTF-8

org.springframework.boot

spring-boot-starter-web

org.mybatis.spring.boot

mybatis-spring-boot-starter

2.0.0

mysql

mysql-connector-java

org.springframework.boot

spring-boot-starter-test

test

org.springframework.boot

spring-boot-starter-security

org.springframework.boot

spring-boot-starter-thymeleaf

org.thymeleaf.extras

thymeleaf-extras-springsecurity5

org.springframework.boot

spring-boot-devtools

true

org.springframework.boot

spring-boot-starter-tomcat

provided

cms

org.springframework.boot

spring-boot-maven-plugin

true

true

新建项目后看一下项目目录结构

936944377b78

目录结构

权限控制我们需要写的类有几个

1:com.simmytech.cms.config下的MyPasswordEncoder

2:com.simmytech.cms.config下的WebSecurityConfig

3:com.simmytech.cms.service下的CustomUserService

4:com.simmytech.cms.service下的MyAccessDecisionManager

5:com.simmytech.cms.service下的MyFilterSecurityInterceptor

6:com.simmytech.cms.service下的MyInvocationSecruityMetadataSourceService

下面我们先数据库用户、角色、权限表的设计和数据库的逻辑操作,然后再和secrity结合控制

数据库表一共由

936944377b78

数据库表

5个表组成,分别是用户表sys_user

936944377b78

用户表

角色表sys_role

936944377b78

角色表

权限表sys_permission

936944377b78

权限表

权限角色关联表sys_permission_role

936944377b78

权限角色关联表

角色用户关联表sys_role_user

936944377b78

角色用户关联表

现在看具体权限相关类的写法

MyPasswordEncoder类用户用户密码加密的类

package com.simmytech.cms.config;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import org.springframework.security.crypto.password.PasswordEncoder;

public class MyPasswordEncoder implements PasswordEncoder {

Log log = LogFactory.getLog(MyPasswordEncoder.class);

BCryptPasswordEncoder bean = new BCryptPasswordEncoder();

@Override

public String encode(CharSequence arg0) {

// TODO Auto-generated method stub

return bean.encode(arg0).toString();

}

@Override

public boolean matches(CharSequence arg0, String arg1) {

// TODO Auto-generated method stub

return bean.matches(arg0, arg1);

}

}

WebSecurityConfig类Security是否过滤的配置

package com.simmytech.cms.config;

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.core.userdetails.UserDetailsService;

import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;

import com.simmytech.cms.service.MyFilterSecurityInterceptor;

@Configuration

@EnableWebSecurity

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired

private MyFilterSecurityInterceptor myFilterSecurityInterceptor;

@Autowired

UserDetailsService customUserService;

@Override

protected void configure(AuthenticationManagerBuilder auth) throws Exception {

auth.userDetailsService(customUserService).passwordEncoder(new MyPasswordEncoder()); // user

// Details

// Service验证

}

@Override

protected void configure(HttpSecurity http) throws Exception {

http.headers().frameOptions().disable()

.and().authorizeRequests().antMatchers("/dist/", "/plugins/","/favicon.ico").permitAll().anyRequest().authenticated() // 任何请求,登录后可以访问

.and().formLogin().loginPage("/login").defaultSuccessUrl("/").failureUrl("/login?error").permitAll() // 登录页面用户任意访问

.and().logout().permitAll(); // 注销行为任意访问

http.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class);

}

}

我的配置是可以iframe访问,静态资源的访问地址不拦截,登录地址,登录成功地址和登录失败的地址配置,其他访问地址全部需要经过权限拦截。

CustomUserService类登录根据用户名获取用户信息

package com.simmytech.cms.service;

import java.util.ArrayList;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.security.core.GrantedAuthority;

import org.springframework.security.core.authority.SimpleGrantedAuthority;

import org.springframework.security.core.userdetails.User;

import org.springframework.security.core.userdetails.UserDetails;

import org.springframework.security.core.userdetails.UserDetailsService;

import org.springframework.security.core.userdetails.UsernameNotFoundException;

import org.springframework.stereotype.Service;

import com.simmytech.cms.model.SysPermission;

import com.simmytech.cms.model.SysUser;

@Service

public class CustomUserService implements UserDetailsService { // 自定义UserDetailsService

@Autowired

private UserService userService;

public UserDetails loadUserByUsername(String username) {

SysUser user = userService.getUserByUserName(username);

if (user != null) {

List permissions = userService.getPermissionByUserId(user.getId());

List grantedAuthorities = new ArrayList<>();

for (SysPermission permission : permissions) {

if (permission != null && permission.getName() != null) {

GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permission.getName());

grantedAuthorities.add(grantedAuthority);

}

}

userService.updateUserLogintime(user.getId());

return new User(user.getUsername(), user.getPassword(), grantedAuthorities);

} else {

throw new UsernameNotFoundException("admin: " + username + " do not exist!");

}

}

}

MyAccessDecisionManager类

package com.simmytech.cms.service;

import org.springframework.security.access.AccessDecisionManager;

import org.springframework.security.access.AccessDeniedException;

import org.springframework.security.access.ConfigAttribute;

import org.springframework.security.authentication.InsufficientAuthenticationException;

import org.springframework.security.core.Authentication;

import org.springframework.security.core.GrantedAuthority;

import org.springframework.stereotype.Service;

import java.util.Collection;

import java.util.Iterator;

@Service

public class MyAccessDecisionManager implements AccessDecisionManager {

@Override

public void decide(Authentication authentication, Object object, Collection configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {

if(null== configAttributes || configAttributes.size() <=0) {

throw new AccessDeniedException("当前访问没有权限");

}

ConfigAttribute c;

String needRole;

for(Iterator iter = configAttributes.iterator(); iter.hasNext(); ) {

c = iter.next();

needRole = c.getAttribute();

for(GrantedAuthority ga : authentication.getAuthorities()) {

if(needRole.trim().equals(ga.getAuthority())) {

return;

}

}

}

throw new AccessDeniedException("当前访问没有权限");

}

@Override

public boolean supports(ConfigAttribute attribute) {

return true;

}

@Override

public boolean supports(Class> clazz) {

return true;

}

}

MyFilterSecurityInterceptor类

package com.simmytech.cms.service;

import javax.servlet.Filter;

import javax.servlet.FilterChain;

import javax.servlet.FilterConfig;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.security.access.SecurityMetadataSource;

import org.springframework.security.access.intercept.AbstractSecurityInterceptor;

import org.springframework.security.access.intercept.InterceptorStatusToken;

import org.springframework.security.web.FilterInvocation;

import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;

import org.springframework.stereotype.Service;

import java.io.IOException;

@Service

public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {

@Autowired

private FilterInvocationSecurityMetadataSource securityMetadataSource;

@Autowired

public void setMyAccessDecisionManager(MyAccessDecisionManager myAccessDecisionManager) {

super.setAccessDecisionManager(myAccessDecisionManager);

}

@Override

public void init(FilterConfig filterConfig) throws ServletException {

}

@Override

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

FilterInvocation fi = new FilterInvocation(request, response, chain);

invoke(fi);

}

public void invoke(FilterInvocation fi) throws IOException, ServletException {

//fi里面有一个被拦截的url

//里面调用MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限

//再调用MyAccessDecisionManager的decide方法来校验用户的权限是否足够

InterceptorStatusToken token = super.beforeInvocation(fi);

try {

//执行下一个拦截器

fi.getChain().doFilter(fi.getRequest(), fi.getResponse());

} finally {

super.afterInvocation(token, null);

}

}

@Override

public void destroy() {

}

@Override

public Class> getSecureObjectClass() {

return FilterInvocation.class;

}

@Override

public SecurityMetadataSource obtainSecurityMetadataSource() {

return this.securityMetadataSource;

}

}

MyInvocationSecurityMetadataSourceService类

package com.simmytech.cms.service;

import java.util.ArrayList;

import java.util.Collection;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.security.access.ConfigAttribute;

import org.springframework.security.access.SecurityConfig;

import org.springframework.security.web.FilterInvocation;

import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;

import org.springframework.stereotype.Service;

import com.simmytech.cms.model.SysPermission;

import com.simmytech.cms.model.SysRole;

@Service

public class MyInvocationSecurityMetadataSourceService implements FilterInvocationSecurityMetadataSource {

@Value("${simmytech.exurl}")

private String exurl;

@Autowired

private UserService userService;

@Override

public Collection getAttributes(Object object) throws IllegalArgumentException {

// 获取当前访问url

String url = ((FilterInvocation) object).getRequestUrl();

int firstQuestionMarkIndex = url.indexOf("?");

if (firstQuestionMarkIndex != -1) {

url = url.substring(0, firstQuestionMarkIndex);

}

if(filter(url)){

return null;

}

List result = new ArrayList<>();

// 查询数据库url匹配的菜单

List menuList = userService.getPermissionByUrl(url);

if (menuList != null && menuList.size() > 0) {

for (SysPermission menu : menuList) {

// 查询拥有该菜单权限的角色列表

List roles = userService.getRoleByPermissionId(menu.getId());

if (roles != null && roles.size() > 0) {

for (SysRole role : roles) {

ConfigAttribute conf = new SecurityConfig(role.getName());

result.add(conf);

}

}

}

}

if(result.isEmpty()){

result.add(new SecurityConfig("ROLE_EMPTY"));

}

return result;

}

@Override

public Collection getAllConfigAttributes() {

return null;

}

@Override

public boolean supports(Class> clazz) {

return true;

}

private boolean filter(String url){

String[] urls=exurl.split(",");

for(String temp:urls){

if(url.indexOf(temp)==0){

return true;

}

}

return false;

}

}

下面开始看controller和登录页的配置

package com.simmytech.cms.web;

import java.util.Calendar;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.RequestMapping;

import com.simmytech.cms.model.SysUser;

import com.simmytech.cms.service.UserService;

import com.simmytech.cms.vo.MenuVo;

@Controller

public class HomeController {

@Autowired

private UserService userService;

@RequestMapping("/")

public String index(Model model){

return "index";

}

@RequestMapping("/login")

public String login(){

return "login";

}

}

controller包含登录页和首页

现在看登录页的登录form

Remember Me

登录

下面看登录成功首页的退出登录功能

当前文章没有包含userService的写法,当然这个可以根据自己的业务来实现。

如果有需要页面权限标签的功能我会单独的文章来展现,这里就不说明了。

动态配置用户角色权限直接的关系需要大家自己来实现了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值