pom
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.22</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.6.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
yml
server:
port: 80
servlet:
contest-path: /
logging:
level:
com.dev.shiro.mapper: debug
spring:
application:
name: springboot-shiro
thymeleaf:
prefix:
classpath: /template
suffix: .html
encoding: UTF-8
cache: false
mode: HTML5
jackson:
#参数意义:
#JsonInclude.Include.ALWAYS 默认
#JsonInclude.Include.NON_DEFAULT 属性为默认值不序列化
#JsonInclude.Include.NON_EMPTY 属性为 空(””) 或者为 NULL 都不序列化
#JsonInclude.Include.NON_NULL 属性为NULL 不序列化
default-property-inclusion: ALWAYS
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
serialization:
WRITE_DATES_AS_TIMESTAMPS: false
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost/simple?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&useSSL=false
username: root
password: 123456
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
shiro:
loginUrl: /login
unauthorizedUrl: /unauth
indexUrl: /index
ShiroConfig
package com.dev.shiro.config;
import com.dev.shiro.shiro.UserRealm;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.authc.LogoutFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @ClassName : ShiroConfig //类名
* @Description : shiro配置 //描述
* @Author : Hao Niu //作者
* @Date: 2020-12-07 14:51 //时间
*/
@Configuration
public class ShiroConfig {
@Value("${shiro.loginUrl}")
private String loginUrl;
@Value("${shiro.indexUrl}")
private String indexUrl;
@Value("${shiro.unauthorizedUrl}")
private String unauthorizedUrl;
@Bean
public SecurityManager securityManager(UserRealm userRealm)
{
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm);
return securityManager;
}
/**
* 自定义 userRealm
*/
@Bean
public UserRealm userRealm()
{
UserRealm userRealm = new UserRealm();
return userRealm;
}
/**
* 退出过滤器
*/
public LogoutFilter logoutFilter()
{
LogoutFilter logoutFilter = new LogoutFilter();
logoutFilter.setRedirectUrl(loginUrl);
return logoutFilter;
}
/**
* Shiro过滤器配置
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager)
{
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// Shiro的核心安全接口,这个属性是必须的
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 身份认证失败,则跳转到登录页面的配置
shiroFilterFactoryBean.setLoginUrl(loginUrl);
shiroFilterFactoryBean.setSuccessUrl(indexUrl);
// 权限认证失败,则跳转到指定页面
shiroFilterFactoryBean.setUnauthorizedUrl(unauthorizedUrl);
// Shiro连接约束配置,即过滤链的定义
LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
// 退出 logout地址,shiro去清除session
filterChainDefinitionMap.put("/logout", "logout");
// “/system” 开头的需要身份认证
filterChainDefinitionMap.put("/system*", "authc");
// “/mobile” 开头的需要角色认证,是“mobile”才允许
filterChainDefinitionMap.put("/mobile*", "roles[mobile]");
// “/platform” 开头的需要权限认证,是“platform:view”才允许
filterChainDefinitionMap.put("/platform*", "perms[\"platform:view\"]");
// 不需要拦截的访问
filterChainDefinitionMap.put("/login", "anon");
Map<String, Filter> filters = new LinkedHashMap<String, Filter>();
// 注销成功,则跳转到指定页面
filters.put("logout", logoutFilter());
shiroFilterFactoryBean.setFilters(filters);
// 所有请求需要认证
filterChainDefinitionMap.put("/**", "user");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
}
UserRealm
package com.dev.shiro.shiro;
import com.dev.shiro.entity.Login;
import com.dev.shiro.service.LoginService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Objects;
/**
* @Description : 用户配置 //描述
* @Author : Hao Niu //作者
*/
@Slf4j
public class UserRealm extends AuthorizingRealm {
@Autowired
private LoginService loginService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
Login login = (Login) pc.getPrimaryPrincipal();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
if (Objects.nonNull(login)){
info.setRoles(loginService.getRoles(login.getLoginName()));
info.setStringPermissions(loginService.getPermissions(login.getLoginName()));
}
return info;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String loginName = (String) token.getPrincipal();
if (loginName.isEmpty() && loginName.isBlank()) {
return null;
}
Login login = loginService.login(loginName);
if(Objects.nonNull(login)){
AuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(login, token.getCredentials(), getName());
return simpleAuthenticationInfo;
}else {
return null;
}
}
}
登录后台
@PostMapping("/login")
public String login_ajax(HttpServletRequest request, Login login){
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(login.getLoginName(),login.getPassword());
Subject subject = SecurityUtils.getSubject();
try {
subject.login(usernamePasswordToken);
request.getSession().setAttribute("user", login);
return "index";
} catch (Exception e) {
e.printStackTrace();
request.getSession().setAttribute("error", e.getMessage());
return "login";
}
}
登录前端
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<form th:action="@{/login}" method="post">
loginName:<input type="text" name="loginName" placeholder="登录名">
password:<input type="password" name="password">
<input type="submit" value="登录" />
</form>
</body>
</html>
GitHub:传送门