整合Shiro
大约 2 分钟Spring全家桶SpringBoot精讲细讲
引入依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.7.1</version>
</dependency>
配置文件
application.yaml
shiro:
loginUrl: toLogin
successUrl: /
自定义UserRealm
public class UserRealm extends AuthorizingRealm {
@Resource
private UserService userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
String username = (String) principalCollection.getPrimaryPrincipal();
// 根据用户名查出角色
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRoles(Arrays.asList("admin", "manager"));
// 根据用户查询权限信息
info.addStringPermissions(Arrays.asList("user:add", "user:delete"));
return info;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
String username = token.getUsername();
// 数据库中查询用户
User user = userService.findUserByName(username);
if (user == null) {
throw new RuntimeException("用户不存在");
}
return new SimpleAuthenticationInfo(token.getUsername(), user.getPassword(),getName());
}
}
config配置类
@Configuration
public class ShiroConfig {
@Bean
public Realm getRealm(){
return new UserRealm();
}
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition(){
DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
chainDefinition.addPathDefinition("/api/**", "anon");
chainDefinition.addPathDefinition("/toLogin", "anon");
chainDefinition.addPathDefinition("/login", "anon");
chainDefinition.addPathDefinition("/**", "authc");
return chainDefinition;
}
}
controller层
@RestController
public class LoginController {
@PostMapping("/login")
public String login(@RequestParam String username,
@RequestParam String password,
@RequestParam(defaultValue = "false") Boolean rememberMe){
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
token.setRememberMe(rememberMe);
try {
subject.login(token);
} catch (UnknownAccountException uae) {
return "用户名错误";
} catch (IncorrectCredentialsException ice) {
return "密码错误";
} catch (LockedAccountException lae) {
return "用户名冻结";
} catch (AuthenticationException ae) {
return "其他错误";
}
return "success";
}
}
前端登录页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>登录</h1>
<form id="loginForm">
用户名:<input type="text" name="username"> <br>
密码:<input type="password" name="password"> <br>
<input type="checkbox" name="rememberMe" value="true"> 记住我<br>
<input type="button" id="loginBtn" value="登录">
</form>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
$("#loginBtn").click(function () {
$.post("login", $("#loginForm").serialize(), function (data) {
console.log(data)
if (data === "success"){
location.href = "/"
}
})
})
</script>
</body>
</html>
controller增加接口权限
@Api(tags = "用户的crud操作api")
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequiresPermissions("user:query")
@ApiOperation("分页查询用户")
@GetMapping("/user")
public PageBean<User> findAllUser(){
// 分页
PageHelper.startPage(1, 2);
List<User> userList = userService.findAllUser();
return new PageBean<>(userList);
}
}
前面UserRealm
配置的用户只有user:add
和user:delete
权限。
info.addStringPermissions(Arrays.asList("user:add", "user:delete"));
而/user
需要user:query
权限,登录之后没有权限访问:

这样在controller层,使用注解
@RequiresPermissions
控制了后端API接口的权限。
shiro整合thymeleaf
依赖导入
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.7.1</version>
</dependency>
<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>
</dependency>
config配置类
@Configuration
public class ShiroConfig {
/**
* shiro方言,支持shiro标签
* @return
*/
@Bean
public ShiroDialect shiroDialect(){
return new ShiroDialect();
}
@Bean
public Realm getRealm(){
return new UserRealm();
}
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition(){
DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
chainDefinition.addPathDefinition("/api/**", "anon");
chainDefinition.addPathDefinition("/toLogin", "anon");
chainDefinition.addPathDefinition("/login", "anon");
chainDefinition.addPathDefinition("/**", "authc");
return chainDefinition;
}
}
html中添加命名空间
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>首页</h1>
<!--用户未登录,显示登录按钮-->
<div shiro:notAuthenticated>
<a style="font-size: xxx-large; font-weight: bold;" th:href="@{~/toLogin}">登录</a> <br>
</div>
<div shiro:hasPermission="user:delete">
<span style="font-size: xxx-large; font-weight: bold;">user:delete</span><br>
</div>
<div shiro:hasPermission="user:update">
<span style="font-size: xxx-large; font-weight: bold;">user:update</span><br>
</div>
<div shiro:hasPermission="user:add">
<span style="font-size: xxx-large; font-weight: bold;">user:add</span><br>
</div>
<div shiro:hasPermission="user:query">
<span style="font-size: xxx-large; font-weight: bold;">user:query</span><br>
</div>
</body>
</html>