当前环境: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字符
以上纯属个人见解,如有问题请联系本人!