Apache Shiro中使用注解来实现角色控制和权限控制(使用SpringBoot实现)

当前环境:jdk1.8 、shiro1.4.1、eclipse

1.添加依赖

	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.9</version>
		</dependency>
		<dependency>
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
			<version>1.1.3</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-core</artifactId>
			<version>1.4.1</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>2.0.0-alpha1</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-simple -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-simple</artifactId>
			<version>2.0.0-alpha1</version>
		</dependency>
		<!-- 使用注解版的权限管理需要开启aop -->
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-aspectj</artifactId>
			<version>1.4.1</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring</artifactId>
			<version>1.4.1</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.8</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
			<version>1.2.4.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
			<version>1.2.4.RELEASE</version>
		</dependency>
	</dependencies>

2.自定义Realm

/**
 * @description 自定义的Realm类用于处理用户的身份验证和用户的授权
 * @author hy
 * @date 2019-10-04
 */
//当前的MyRealm可以继承其他的类也可以实现其他的类
public class MyRealm extends AuthorizingRealm {
	
	MySQLData mysqlData;
	
	public MyRealm(MySQLData mysqlData) {
		this.mysqlData=mysqlData;
	}

	// 认证用户,就是校验用户的用户名和密码
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		// 通过用户的令牌获取当前用户输入的用户名和密码
		UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
		String username = usernamePasswordToken.getUsername();
		String password = new String(usernamePasswordToken.getPassword());
		System.out.println("username:" + username);
		System.out.println("password:" + password);

		
		User loginUser=getUserByUserName(username);
		
		if(loginUser==null) {
			System.out.println("认证失败!");
			return null;
		}else {
			if(loginUser.getPasseword().equals(password)) {
				System.out.println("认证成功!");
				return new SimpleAccount(username, password, toString());
			}
			return null;
		}
		
	}
	
	//通过用户名获取用户
	public User getUserByUserName(String username) {
		Collection<User> users = mysqlData.findAll();
		User loginUser=null;
		for (User user : users) {
			if(user.getUsername().equals(username)) {
				loginUser=user;
				break;
			}
		}
		return loginUser;
	}

	// 这里是授权管理,通过登陆后的用户名获取用户对应的权限,通过用户名获取用户的角色和权限

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		System.out.println(principals); // 获取用户名
		String username = (String) (principals.getPrimaryPrincipal());
		// 这里不能使用simpleAccout类,虽然当前这个类也实现了AuthorizationInfo接口,但是使用的时候报错
		SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();// 必须为SimpleAuthorizationInfo类
	
		User loginUser = getUserByUserName(username);

		authorizationInfo.addRole(loginUser.getRoleName());
		authorizationInfo.addStringPermission(loginUser.getPermissionName());
		return authorizationInfo;
	}

}

3.模拟数据库中的数据MySQLData

//用于模拟MySQL中的数据
public class MySQLData {
	private Map<Integer, User> userData=new HashMap<Integer, User>();
	{
		userData.put(1, new User(1, "zhangsan", "123456", 22, LocalDate.of(2019, 10, 5), true, "user", "select,update,add"));
		userData.put(2, new User(2, "lisi", "123456", 25, LocalDate.of(2019, 10, 6), false, "guest", "select"));
		userData.put(3, new User(3, "wangwu", "123456", 26, LocalDate.of(2019, 10, 7), true, "guest", "select"));
		userData.put(4, new User(4, "admin", "123456", 27, LocalDate.of(2019, 10,8), false, "admin", "*"));	
	}
	
	public void addUser(User user) {
		userData.put(user.getId(), user);
	}
	
	public void deleteUserById(Integer id) {
		userData.remove(id);
	}
	
	public User selectUserById(Integer id) {
		return userData.get(id);
	}
	
	public void updateUser(User user) {
		userData.put(user.getId(), user);
	}
	
	public Collection<User> findAll(){
		return userData.values();
	}
}

4.创建实体类User

import java.time.LocalDate;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@AllArgsConstructor
@Data
public class User {
	private Integer id;
	private String username;//用户名
	private String passeword;//密码
	private Integer age;//年龄
	private LocalDate birth;//出生年月日
	private Boolean onwork;//是否在职
	private String roleName;
	private String permissionName;
}

5.创建Shiro的配置类

import java.util.HashMap;
import java.util.Map;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.hy.shiro.annotation.MyRealm;
import com.hy.shiro.annotation.data.MySQLData;

@Configuration
public class ApplicationConfig {
	
	@Bean
	public MySQLData getMySQLData() {
		return new MySQLData();
	}
	
	@Bean
	public Realm getRealm() {
		return new MyRealm(getMySQLData());
	}
	
	//创建校验管理器
	@Bean
	public SecurityManager securityManager() {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setRealm(getRealm());
		return securityManager;
	}
	
	//创建Shiro过滤器
	@Bean
	public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		shiroFilterFactoryBean.setSecurityManager(securityManager());
		Map<String,String> map = new HashMap<String, String>();
		//登出
		map.put("/logout","logout");
		//对所有用户认证
		map.put("/**","authc");
		//登录页面使用get方式
		shiroFilterFactoryBean.setLoginUrl("/login");
		//首页get方式
		shiroFilterFactoryBean.setSuccessUrl("/index");
		//错误页面,认证不通过跳转
		shiroFilterFactoryBean.setUnauthorizedUrl("/error");
		shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
		return shiroFilterFactoryBean;
	}

	//让当前的项目可以使用shiro的注解控制用户角色和权限
	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
		authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
		return authorizationAttributeSourceAdvisor;
	}

}

6.创建controller层

/**
 * @description 模拟访问html页面
 * @author hy
 * @date 2019-10-04
 */
@Controller
public class HtmlPageController {
	@Autowired
	MySQLData mysqlData;
	
	
	//访问login页面的时候是get的请求,主要是用于访问login页面
    @RequestMapping(value = "/login",method = RequestMethod.GET)
    public String login(){
        return "login";
    }

    //post登录,这里的必须使用post方式进行身份认证,这里的login与上面不一样
    @RequestMapping(value = "/login",method = RequestMethod.POST)
    public String login(@RequestParam Map<String,Object> map){
        //添加用户认证信息
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(
                map.get("username").toString(),
                map.get("password").toString());
        //进行验证,这里可以捕获异常,然后返回对应信息
        subject.login(usernamePasswordToken);
        return "login";
    }

    @RequestMapping(value = "/index")
    public String index(){
        return "index";
    }
	
	
	@RequestMapping("/admin")
	//访问管理页面需要admin角色
	@RequiresRoles(value = {"admin"})
	@ResponseBody
	public String goToManagerPage() {
		return "访问后台管理页面,成功!";
	}
	
	@RequestMapping("/user")
	@ResponseBody
	//访问用户页面,需要user角色
	@RequiresRoles(value = {"user","admin"},logical = Logical.OR)
	public String goToUserPage() {
		return "访问用户页面,成功!";
	}
	
	@RequestMapping("/addUser")
	@ResponseBody
	@RequiresPermissions(value = {"add"})
	public String addUserOption(User user) {
		mysqlData.addUser(user);
		return "执行添加用户操作";
	}
	
	@RequestMapping("/deleteUser")
	@ResponseBody
	@RequiresPermissions(value = {"delete"})
	public String deleteUserOption(Integer id) {
		mysqlData.deleteUserById(id);
		return "执行删除用户操作";
	}
	
	@RequestMapping("/findUserById")
	@ResponseBody
	@RequiresRoles(value = {"user","admin"},logical = Logical.OR)
	@RequiresPermissions(value = {"select"})
	public User selectUserByIdOption(Integer id) {
		System.out.println("执行查询用户操作");
		return mysqlData.selectUserById(id);	
	}
	
	@RequestMapping("/updateUser")
	@ResponseBody
	@RequiresPermissions(value = {"update"})
	public String updateUserOption(User user) {
		mysqlData.updateUser(user);
		return "执行更新用户操作";
	}
	
	@RequestMapping("/findAll")
	@ResponseBody
	@RequiresRoles(value = {"admin"})
	public Collection<User> findAllOption(){
		System.out.println("执行查询所有用户操作");
		return mysqlData.findAll();
	}
	
}

7.创建入口类

/**
 * @description 在shrio中使用注解的方式来实现权限的管理
 * @author hy
 * @date 2019-10-04
 */
@SpringBootApplication
public class ShiroAnnotationApp 
{
	public static void main(String[] args) {
		SpringApplication.run(ShiroAnnotationApp.class, args);
	}
}

8.创建简单的html页面

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8"/>
		<title></title>
	</head>
	<body>
		出现错误!或没有权限!
	</body>
</html>

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8"/>
		<title></title>
	</head>
	<body>
		登录成功!
	</body>
</html>

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8"/>
		<title></title>
	</head>
	<body>
		<form action="/login" method="post">
			<table border="1">
				<tr><td>用户名:<input type="text" name="username"/></td></tr>
				<tr><td>密码:<input type="text" name="password"/></td></tr>
				<tr><td><input type="submit"  value="提交"/></td></tr>
			</table>
		</form>
	</body>
</html>

9.测试

测试结果这里就不现实了,但是这个实现了基本的功能,实现了对用于的角色和权限的控制

10.总结

1.在SpringBoot中使用注解的时候需要使用AuthorizationAttributeSourceAdvisor 这个类,这个类是开启注解角色和权限的主要类!

2.在方法上面使用@RequiredRoles或者@RequiredPermissions来控制,可以使用logical = Logical.OR或者logical = Logical.AND方式来实现或和并

3.注意在需要开启Filter:ShiroFilterFactoryBean(这个类),并在其中添加其他的页面,必须指明登录页面和登录成功页面以及错误页面

4.当前的login方法返回的login页面使用get请求,在我们使用login页面的时候可以使用post请求访问login来实现用户的登录

5.用户的登录还是通过SecurityUtil获取Subject来进行登录,并返回的为login字符

以上纯属个人见解,如有问题请联系本人!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值