Springboot-cli 开发脚手架系列
Springboot优雅的整合Shiro进行登录校验,权限认证(附源码下载)
简介
Springboo配置Shiro进行登录校验,权限认证,附demo演示。
前言
我们致力于让开发者快速搭建基础环境并让应用跑起来,提供使用示例供使用者参考,让初学者快速上手。 本博客项目源码地址:
1. 环境
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
server:
port: 9999
servlet:
session:
tracking-modes: COOKIE
spring:
thymeleaf:
cache: false
prefix: classpath:/templates/
mode: HTML
2. 简介
Shiro三大功能模块
- Subject
认证主体,通常指用户(把操做交给SecurityManager)。 - SecurityManager
安全管理器,安全管理器,管理全部Subject,能够配合内部安全组件(关联Realm) - Realm
域对象,用于进行权限信息的验证,shiro连接数据的桥梁,如我们的登录校验,权限校验就在Realm进行定义。
3. Realm配置
@Data
@Accessors(chain = true)
public class User {
private Long userId;
private String username;
private String password;
private String name;
}
- 重写
AuthorizingRealm 中登录校验doGetAuthenticationInfo 及授权doGetAuthorizationInfo 方法,编写我们自定义的校验逻辑。
public class UserRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermission("vip");
return info;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
String username = token.getUsername();
String password = String.valueOf(token.getPassword());
User user = this.getUser();
if (!user.getUsername().equals(username)) {
throw new UnknownAccountException("用户不存在");
} else if (!user.getPassword().equals(password)) {
throw new IncorrectCredentialsException("密码错误");
}
return new SimpleAuthenticationInfo(user, password, getName());
}
private User getUser() {
return new User()
.setName("admin")
.setUserId(1L)
.setUsername("admin")
.setPassword("123456");
}
}
4. 核心配置
/** * Shiro内置过滤器,能够实现拦截器相关的拦截器 * 经常使用的过滤器: * anon:无需认证(登陆)能够访问 * authc:必须认证才能够访问 * user:若是使用rememberMe的功能能够直接访问 * perms:该资源必须获得资源权限才能够访问,格式 perms[权限1,权限2] * role:该资源必须获得角色权限才能够访问 **/
@Configuration
public class ShiroConfig {
private final static String ANON = "anon";
private final static String AUTHC = "authc";
private final static String PERMS = "perms";
@Bean(name = "userRealm")
public UserRealm userRealm() {
return new UserRealm();
}
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm);
return securityManager;
}
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(defaultWebSecurityManager);
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/index", ANON);
filterMap.put("/userInfo", PERMS + "[vip]");
filterMap.put("/table2", AUTHC);
filterMap.put("/table3", PERMS + "[vip2]");
bean.setFilterChainDefinitionMap(filterMap);
bean.setLoginUrl("/login");
bean.setUnauthorizedUrl("/unAuth");
return bean;
}
@Bean
public ShiroDialect shiroDialect() {
return new ShiroDialect();
}
}
5. 接口编写
@Controller
public class IndexController {
@RequestMapping({"/", "/index"})
public String index(Model model) {
model.addAttribute("msg", "hello,shiro");
return "/index";
}
@RequestMapping("/userInfo")
public String table1(Model model) {
return "userInfo";
}
@RequestMapping("/table")
public String table(Model model) {
return "table";
}
@GetMapping("/login")
public String login() {
return "login";
}
@PostMapping(value = "/doLogin")
public String doLogin(@RequestParam("username") String username, @RequestParam("password") String password, Model model) {
Subject subject = SecurityUtils.getSubject();
String msg = "";
if (!subject.isAuthenticated()) {
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
subject.login(token);
} catch (Exception e) {
e.printStackTrace();
msg = "账号或密码错误";
}
if (msg.isEmpty()) {
return "redirect:/index";
} else {
model.addAttribute("errorMsg", msg);
return "login";
}
}
return "/login";
}
@GetMapping("/logout")
public String logout() {
SecurityUtils.getSubject().logout();
return "index";
}
@GetMapping("/unAuth")
public String unAuth() {
return "unAuth";
}
}
6. 网页资源
- 在
resources 中创建templates 文件夹存放页面资源 index.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<html xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>首页</h1>
<shiro:authenticated>
<p>用户已登录</p> <a th:href="@{/logout}">退出登录</a>
</shiro:authenticated>
<shiro:notAuthenticated>
<p>用户未登录</p>
</shiro:notAuthenticated>
<br/>
<a th:href="@{/userInfo}">用户信息</a>
<a th:href="@{/table}">table</a>
</body>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>登陆页</title>
</head>
<body>
<div>
<p th:text="${errorMsg}"></p>
<form action="/doLogin" method="post">
<h2>登陆页</h2>
<h6>账号:admin,密码:123456</h6>
<input type="text" id="username" name="username" placeholder="admin">
<input type="password" id="password" name="password" placeholder="123456">
<button type="submit">登陆</button>
</form>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
<meta charset="UTF-8">
<title>table1</title>
</head>
<body>
<h1>用户信息</h1>
用户名:<shiro:principal property="username"/>
<br/>
用户完整信息: <shiro:principal/>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>table</title>
</head>
<body>
<h1>table</h1>
</body>
</html>
7. 效果演示
- 启动项目浏览器输入
127.0.0.1:9999 - 当我们点击用户信息和table时会自动跳转登录页面
- 登录成功后
- 获取用户信息
此处获取的就是我们就是我们前面doGetAuthenticationInfo 方法返回的用户信息,这里为了演示就全部返回了,实际生产中密码是不能返回的。
8. 源码分享
本项目已收录
|