Apache Shiro是一个开源的轻量级的java安全框架,它提供身份验证,授权,密码管理以及会话管理功能等。相对于SpringSecurity,Shiro框架跟家直观,易用,同时也能提供健壮的安全性,在传统SSM框架中,手动配置Shiro的步骤还是比较多的,针对Springboot,shiro官方提供了shiro-spring-boot-web-starter 的使用步骤。
整合Shiro
1.加依赖pom.xml
<!--安全认证 shiro-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.theborakompanioni/thymeleaf-extras-shiro -->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
<!--webMvc-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
2.配置shiro文件,application.yml
server:
port: 8808
#安全认证 shiro
shiro:
enabled: true #开启shiro默认true
web:
enabled: true #开启shiro web 默认true
loginUrl: /login #登录地址 、默认/login.jsp
successUrl: /index #登录成功地址.默认/
unauthorizedUrl: /unauthorized #为授权默认跳转的地址
sessionManager:
sessionIdCookieEnabled: true #是否允许Cookie 实现绘画跟踪,默认为true
sessionIdUrlRewritingEnabled: true
spring:
thymeleaf:
prefix: classpath:/templates/
servlet:
content-type: text/html
suffix: .html
encoding: utf-8
cache: false
mode: LEGACYHTML5
3.配置类,提供两个Bean即可,这里配置了两个用户,sang/123,admin/123分别对应角色user&admin,user具有read权限,admin具有read,write权限。
package com.example.demo.config;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.realm.text.TextConfigurationRealm;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ShiroConfig {
@Bean
public Realm realm(){
TextConfigurationRealm realm = new TextConfigurationRealm();
realm.setUserDefinitions("sang=123,user\n admin=123,admin");
realm.setRoleDefinitions("admin=read,write\n user=read");
return realm;
}
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition(){
DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
chainDefinition.addPathDefinition("/login","anon");
chainDefinition.addPathDefinition("/doLogin","anon");
chainDefinition.addPathDefinition("/logout","logout");
chainDefinition.addPathDefinition("/**","authc");
return chainDefinition;
}
@Bean
public ShiroDialect shiroDialect(){
return new ShiroDialect();
}
}
4.编写接口controller.java
package com.example.demo.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class UserController {
@RequestMapping("/doLogin")
public String doLogin(String username, String password, Model model){
UsernamePasswordToken token= new UsernamePasswordToken(username,password);
Subject subject = SecurityUtils.getSubject();
try {
subject.login(token);
} catch (AuthenticationException e) {
e.printStackTrace();
model.addAttribute("error", "用户名或密码输入错误");
return "login";
}
return "redirect:/index";
}
@RequiresRoles("/admin")
@GetMapping("/admin")
public String admin(){
return "admin";
}
@RequiresRoles(value = {"admin","user"},logical = Logical.OR)
@GetMapping("/user")
public String user(){
return "user";
}
}
5.配置不需要角色就能访问的接口
package com.example.demo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registrt){
registrt.addViewController("/login").setViewName("login");
registrt.addViewController("/index").setViewName("index");
registrt.addViewController("/unauthorized").setViewName("unauthorized");
}
}
6.编写全局异常处理器进行全局异常处理
package com.example.demo.config;
import org.apache.shiro.authz.AuthorizationException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
@ControllerAdvice
public class ExceptionController {
@ExceptionHandler(AuthorizationException.class)
public ModelAndView error(AuthorizationException e){
ModelAndView mv = new ModelAndView("unauthorized");
mv.addObject("error",e.getMessage());
return mv;
}
}
7.编写5个前端页面resources/templates
index.html
<!DOCTYPE html>
<html lang="en" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>Hello,<shiro:principal/></h2>
<h2><a href="/logout">注销登录</a> </h2>
<h2><a shiro:hasRole="admin" href="/admin" >管理员页面</a></h2>
<h2><a shiro:hasAnyRoles="admin,user" href="/user" >普通用户页面</a></h2>
<h2><a shiro:hasAllRoles="admin" href="/admin">CYC</a></h2>
</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<form action="/doLogin" method="post">
<input type="text" name="username"><br/>
<input type="password" name="password"><br/>
<div th:text="${error}"></div>
<input type="submit" value="登录"/>
</form>
</div>
</body>
</html>
user.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body><h1>普通用户页面</h1>
</body>
</html>
admin.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>管理员页面</h1>
</body>
</html>
unauthorized.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>未获得授权,非法访问</h1>
<div>
<!--/*@thymesVar id="error" type="aj"*/-->
<h1 th:text="${error}"></h1>
</div>
</body>
</html>
8.启动项目,访问localhost:8808/login-----------------------分别使用sang / 123 & admin / 123 登录
如果你以user登录,然后在地址栏中访问admin结果为不能访问