社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
个人整合 有问题请评论 及时修改 共同进步
能查找这个整合的都是有基础的 就直接干货
项目目录
springboot的启动文件创建项目时都生成 略过
maven 的pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.test</groupId>
<artifactId>SpringBootshiro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SpringBootshiro</name>
<description>Spring Boot test 3</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--SpringBoot Web支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--SpringBoot 测试支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- websocket 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!--添加tomcat支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
<!-- reids -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 阿里Json 包 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>
<!-- 安全框架shiro 支持 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.1</version>
</dependency>
<!-- shiro 缓存框架 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.4.0</version>
</dependency>
<!-- shiro+redis缓存插件 -->
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis</artifactId>
<version>2.4.2.1-RELEASE</version>
</dependency>
<!-- shiro 标签支持 -->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<!-- mybatis 支持 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<!-- oracle 支持 -->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.3</version>
</dependency>
<!-- 获取硬件信息状态 -->
<dependency>
<groupId>org.fusesource</groupId>
<artifactId>sigar</artifactId>
<version>1.6.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!--打包的时候, 略过test, 不运行-->
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
</build>
</project>
配置文件 application.properties
#内置tomcat 配置
server.port=80
server.tomcat.uri-encoding=utf-8
spring.main.allow-bean-definition-overriding=true
# 数据源连接
spring.datasource.driver-class-name: oracle.jdbc.driver.OracleDriver
spring.datasource.url: jdbc:oracle:thin:@127.0.0.1:1521:TEST
spring.datasource.username: arch
spring.datasource.password: manager
#thymeleaf 组件配置
spring.thymeleaf.cache=false
#spring.thymeleaf.prefix=classpath:/templates/*
#spring.thymeleaf.check-template-location=true
#spring.thymeleaf.suffix=.html
#spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.mode=HTML5
#spring.thymeleaf.servlet.content-type=text/html
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=localhost
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=manager
# 连接超时时间(毫秒)
spring.redis.timeout=0
#mybatis配置文件路径
mybatis.mapper-locations=classpath:mappers/*.xml
shiro的配置类
package com.test.config;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.test.shiro.CustomRealm;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
@Configuration
public class ShiroConfig {
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//登录页面
shiroFilterFactoryBean.setLoginUrl("/login.html");
//未授权页面
shiroFilterFactoryBean.setUnauthorizedUrl("/error/403.html");
//登录成功页面
//shiroFilterFactoryBean.setSuccessUrl("/index.html");
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
// <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
filterChainDefinitionMap.put("/login", "anon");
filterChainDefinitionMap.put("/user/login", "anon");
filterChainDefinitionMap.put("/logout", "logout");
filterChainDefinitionMap.put("/sock.html", "anon");
filterChainDefinitionMap.put("/helloSocket/**", "user");
//拦截其他所有路径和页面
filterChainDefinitionMap.put("/**", "user");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();
//设置realm
defaultSecurityManager.setRealm(customRealm());
//自定义缓存实现 redis
defaultSecurityManager.setCacheManager(cacheManager());
//自定义session管理 redis
defaultSecurityManager.setSessionManager(sessionManager());
//记住我 自定义配置
defaultSecurityManager.setRememberMeManager(rememberMeManager());
return defaultSecurityManager;
}
@Bean
public CustomRealm customRealm() {
CustomRealm customRealm = new CustomRealm();
customRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return customRealm;
}
/**
* 加密
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
// 散列算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashAlgorithmName("md5");
// 散列的次数,比如散列两次,相当于 md5(md5(""));
hashedCredentialsMatcher.setHashIterations(1024);
return hashedCredentialsMatcher;
}
/**
* cacheManager 缓存 redis实现
* 使用的是shiro-redis开源插件
*
* @return
*/
public RedisCacheManager cacheManager() {
RedisCacheManager redisCacheManager = new RedisCacheManager();
redisCacheManager.setRedisManager(redisManager());
return redisCacheManager;
}
/**
* 配置shiro redisManager
* 使用的是shiro-redis开源插件
*
* @return
*/
public RedisManager redisManager() {
RedisManager redisManager = new RedisManager();
redisManager.setHost("localhost");
redisManager.setPort(6379);
redisManager.setExpire(1800);// 配置缓存过期时间
redisManager.setTimeout(0);
redisManager.setPassword("manager");
return redisManager;
}
/**
* Session Manager
* 使用的是shiro-redis开源插件
*/
@Bean
public DefaultWebSessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionDAO(redisSessionDAO());
sessionManager.setDeleteInvalidSessions(true);//删除过期session
sessionManager.setGlobalSessionTimeout(24 * 60 * 60 * 1000);//session过期时间
sessionManager.setSessionIdCookie(rememberMeCookie());
return sessionManager;
}
/**
* RedisSessionDAO shiro sessionDao层的实现 通过redis
* 使用的是shiro-redis开源插件
*/
@Bean
public RedisSessionDAO redisSessionDAO() {
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
redisSessionDAO.setRedisManager(redisManager());
return redisSessionDAO;
}
@Bean
public SimpleCookie rememberMeCookie(){
//这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
simpleCookie.setHttpOnly(true);
//<!-- 记住我cookie生效时间1天 ,单位秒;-->
//simpleCookie.setMaxAge(24 * 60 * 60);
simpleCookie.setMaxAge(10);
return simpleCookie;
}
@Bean
public CookieRememberMeManager rememberMeManager(){
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
//rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
cookieRememberMeManager.setCipherKey("ZHANKXIAOHEI_WST".getBytes());
return cookieRememberMeManager;
}
@Bean
public ShiroDialect shiroDialect() {
return new ShiroDialect();
}
}
shiro的登录处理
package com.test.shiro;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.test.entity.User;
import com.test.service.IUserService;
import java.util.*;
@Component("authenticator")
public class CustomRealm extends AuthorizingRealm {
private static Logger logger = LoggerFactory.getLogger(CustomRealm.class);
@Autowired
private IUserService userServic;
/**
* 权限认证
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
logger.info("--------------------权限认证------------------------------------------------");
// TODO Auto-generated method stub
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
User user = (User) principals.getPrimaryPrincipal();
System.out.println("权限" + user);
Set<String> roles = new HashSet<>();
return authorizationInfo;
}
/**
* 用户认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
logger.info("--------------------用户认证------------------------------------------------");
SimpleAuthenticationInfo info = null;
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
String username = upToken.getUsername();
//从数据库中获取用户数据
User user = userServic.AccountLogin(username);
System.out.println(user);
if(user==null) {
throw new UnknownAccountException("用户不存在!");
}
if(user.getUt_forbidden().equals(0)) {
throw new LockedAccountException("用户被锁定");
}
//shiro对比密码
info = new SimpleAuthenticationInfo(user,user.getUt_passwrod(),ByteSource.Util.bytes(user.getUt_account()),getName());
return info;
}
public static void main(String[] args) {
String hashAlgorithmName = "MD5";
Object credentials = "123456";
Object salt = ByteSource.Util.bytes("admin");
int hashIterations = 1024;
Object result = new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);
System.out.println(result);
}
}
从数据库中获取 用户信息 和权限信息自行处理 (我本地有oracle数据库我就用的这个)
注:如果不开启缓存,没出现权限的认证都会去数据库中调取数据。虽说这样权限是实时的权限,但是会大大的增加数据库的消耗
登录的控制层
package com.test.Controller;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.test.entity.User;
import com.test.service.IUserService;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private IUserService userServic;
@RequestMapping("/login")
public String AccountLogin(HttpSession session,String username,String password,String rem, HttpServletResponse response) {
Subject currentUser = SecurityUtils.getSubject();
if (!currentUser.isAuthenticated()) {
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
if(rem == null) {
token.setRememberMe(false);
}else {
token.setRememberMe(true);
}
try {
currentUser.login(token);
User user = (User) currentUser.getPrincipal();
System.out.println(user);
session.setAttribute("user", user);
try {
response.sendRedirect("/");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}catch(UnknownAccountException ue) {
System.out.println(ue.getMessage());
return ue.getMessage();
}catch(IncorrectCredentialsException e) {
System.out.println("账户名或密码错误");
return "账户名或密码错误";
}catch (AuthenticationException e) {
System.out.println("登录失败"+ e.getMessage());
return e.getMessage();
}
}
return "redirect:/";
}
}
这里的记住我没有配置成自动的
shiro的前台登录页面
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
<h4>Login Page</h4>
<form action="user/login" method="POST">
username: <input type="text" name="username"/>
<br><br>
password: <input type="password" name="password"/>
<br><br>
<input type="checkbox" value="true" name="rem" >记住我
<br><br>
<input type="submit" value="Submit"/>
</form>
</body>
</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>
</head>
<body>
session:<h1 th:text="${session.user.ut_name}"></h1>
Welcome: <shiro:principal property="ut_name"></shiro:principal>
<shiro:hasRole name="admin">
<br><br>
<a href="sock.html">Admin Page</a>
</shiro:hasRole>
<br><br>
<a href="/logout">Logout</a>
</body>
</html>
注:html的标签的属性一定要写上 要不shiro的标签用不了
shiro的配置示例就结束了 下面在框架中加入websocket的配置
websocket的配置文件
package com.test.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
写个简单的测试
package com.test.socket;
import java.io.IOException;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import org.springframework.stereotype.Component;
@Component
@ServerEndpoint(value = "/helloSocket/{userid}")
public class MyWebSocketServer {
Session session ;
String userid;
/***
* 当建立链接时,调用的方法.
* @param session
* @throws IOException
*/
@OnOpen
public void open(Session session , @PathParam("userid") String userid) throws IOException {
System.out.println("当前session的id是:" + session.getId());
System.out.println(userid);
this.session = session;
this.userid = userid;
session.getBasicRemote().sendText("连接唱功");
WebSocketMapUtil.put(userid, this);
WebSocketMapUtil.sendAll(userid + "登录");
}
/***
* 处理消息的方法.
* @param session
*/
@OnMessage
public void message(Session session, String data) {
System.out.println("当前session的id是:" + session.getId());
System.out.println("从前端页面传过来的数据是:" + data);
}
@OnClose
public void close(Session session) {
System.out.println("退出的id是:" + session.getId() +" id:"+userid);
WebSocketMapUtil.remove(userid);
WebSocketMapUtil.sendAll(userid + "退出");
}
/**
* 向客户端发送信息
*/
public void sendMessage(String msg) {
try {
session.getBasicRemote().sendText(msg);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
package com.test.socket;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class WebSocketMapUtil {
public static Map<String, MyWebSocketServer> webSocketMap = new HashMap<>();
public static void put(String key, MyWebSocketServer myWebSocketServer){
webSocketMap.put(key, myWebSocketServer);
}
public static MyWebSocketServer get(String key){
return webSocketMap.get(key);
}
public static void remove(String key){
webSocketMap.remove(key);
}
public static Collection<MyWebSocketServer> getValues(){
return webSocketMap.values();
}
public static void sendAll(String msg) {
//session.getBasicRemote().sendText("连接唱功");
System.out.println("当前在线人数:" + webSocketMap.size());
for(Map.Entry<String, MyWebSocketServer> entry: webSocketMap.entrySet()) {
//System.out.println("在线用户" + entry.getKey());
try {
entry.getValue().session.getBasicRemote().sendText(msg);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
前台测试页面
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Charles-WebSocket</title>
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript">
var websocket = null;
var target = "/helloSocket/";
function buildConnection(){
var sendmsg = document.getElementById("userid").value;
if('WebSocket' in window) {
websocket = new WebSocket("ws://" + window.location.host +target + sendmsg);
} else if('MozWebSocket' in window) {
websocket = MozWebSocket("ws://" + window.location.host +target + sendmsg);
} else {
window.alert("浏览器不支持WebSocket");
}
websocket.onmessage = function(ev){ //获取后端响应
console.log(ev.data);
$("#content").append(ev.data+"<br/>");
};
websocket.onclose = function(ev){
console.log("close");
};
websocket.onerror = function(ev){
console.log("error");
};
}
// 往后台服务器发送消息.
function sendMessage() {
var sendmsg = document.getElementById("sendMsg").value;
console.log("发送的消息:" + sendmsg);
// 发送至后台服务器中.
websocket.send(sendmsg);
}
</script>
</head>
<body>
<input id="userid"><button οnclick="buildConnection();">开始建立链接</button>
<hr>
<div id="content" style="
border: 1px solid black; width: 400px; height: 300px;
float: left;
" ></div>
<div id="userList" style="
border: 1px solid black; width: 100px; height: 300px;
float:left;
" ></div>
<div style="clear: both;" >
<input id="sendMsg" /><button οnclick="sendMessage();" >send</button>
</div>
</body>
</html>
项目源码的百度网盘
链接:https://pan.baidu.com/s/1U3xDd8aIuREMOAHrFNM5_g
提取码:nqiv
有条件的csdn上支持一下5积分
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!