Shiro有三个主题,Subject,安全管理器,Realm域;
subject:存储登录名/邮箱/手机号等主体标识和密码;
安全管理器:与subject交互
realm域:一般自定义,复写登录方法和授权方法
建表语句:
CREATE TABLE zz_user
(
id
int(11) NOT NULL AUTO_INCREMENT,
username
varchar(255) DEFAULT NULL,
password
varchar(255) DEFAULT NULL,
PRIMARY KEY (id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE zz_role
(
role_id
int(11) NOT NULL AUTO_INCREMENT,
role_name
varchar(255) DEFAULT NULL,
user_id
int(11) DEFAULT NULL,
PRIMARY KEY (role_id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE zz_permission
(
permission_id
int(11) NOT NULL AUTO_INCREMENT,
permission_name
varchar(255) DEFAULT NULL,
role_id
int(11) DEFAULT NULL,
PRIMARY KEY (permission_id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
依赖:
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>RELEASE</version>
</dependency>
自定义Realm域
//自定义Realm继承并复写其登录,权限操作
public class MyRealm extends AuthorizingRealm {
@Autowired
private ShiroMapper shiroMapper;
@Override
//权限认证,即登录过后,每个身份不一定,对应的所能看的页面也不一样。
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取主体标识
String username = (String) principalCollection.getPrimaryPrincipal();
//用AuthorizationInfo接口实现
AuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo();
//设置角色
Set<String> roles= shiroMapper.selectRolesByUser(username);
((SimpleAuthorizationInfo) authorizationInfo).setRoles(roles);
//设置权限
Set<String> permissions=shiroMapper.selectPermissionsByUser(username);
((SimpleAuthorizationInfo) authorizationInfo).setStringPermissions(permissions);
return authorizationInfo;
}
@Override
//身份认证。即登录通过账号和密码验证登陆人的身份信息。
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//根据token获取接口传入的用户名和密码
String username = (String) authenticationToken.getPrincipal();
String credentials = (String) authenticationToken.getCredentials();
//MD5加密(盐为当前用户名+666)
String inputPassword = MD5Util.encryptPassword(username, credentials, username+666);
//获取正确的密码
String password = (String) shiroMapper.selectUserByUsernameAndPassword(username).get("password");
if(inputPassword.equals(password)){
Map<String, Object> map=new HashMap<>();
map.put("username",username);
map.put("password",password);
//登陆成功,存进session
SecurityUtils.getSubject().getSession().setAttribute("user",map);
//返回
AuthenticationInfo authenticationInfo=new SimpleAuthenticationInfo(username,password,"MyRealm");
return authenticationInfo;
}
return null;
}
bean注入
@Bean
public MyRealm myRealm(){
return new MyRealm();
}
@Bean
public SecurityManager securityManager(){
//web应用使用DefaultWebSecurityManager
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(myRealm());
return defaultWebSecurityManager;
}
配置shiro过滤器
public class ShiroConfig {
/**
* 注入 Shiro 过滤器
* @param securityManager 安全管理器
* @return ShiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
// 定义 shiroFactoryBean
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
// 设置自定义的 securityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 设置默认登录的 URL,身份认证失败会访问该 URL
shiroFilterFactoryBean.setLoginUrl("/login");
// 设置成功之后要跳转的链接
shiroFilterFactoryBean.setSuccessUrl("/success");
// 设置未授权界面,权限认证失败会访问该 URL
shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
// LinkedHashMap 是有序的,进行顺序拦截器配置
Map<String,String> filterChainMap = new LinkedHashMap<>();
// 配置可以匿名访问的地址,可以根据实际情况自己添加,放行一些静态资源等,anon 表示放行
filterChainMap.put("/css/**", "anon");
filterChainMap.put("/imgs/**", "anon");
filterChainMap.put("/js/**", "anon");
filterChainMap.put("/swagger-*/**", "anon");
filterChainMap.put("/swagger-ui.html/**", "anon");
// 登录 URL 放行
filterChainMap.put("/login", "anon");
// 以“/user/admin” 开头的用户需要身份认证,authc 表示要进行身份认证
filterChainMap.put("/user/admin*", "authc");
// “/user/student” 开头的用户需要角色认证,是“admin”才允许
filterChainMap.put("/user/student*/**", "roles[admin]");
// “/user/teacher” 开头的用户需要权限认证,是“user:create”才允许
filterChainMap.put("/user/teacher*/**", "perms[\"user:create\"]");
// 配置 logout 过滤器
filterChainMap.put("/logout", "logout");
// 设置 shiroFilterFactoryBean 的 FilterChainDefinitionMap
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainMap);
log.info("====shiroFilterFactoryBean注册完成====");
return shiroFilterFactoryBean;
}
@RequestMapping(value = "/login")
@Slf4j
public class ShiroController {
@RequestMapping(method = RequestMethod.GET,value = "/{username}/{password}")
public Integer shiro(@PathVariable String username,@PathVariable String password) {
// 从SecurityUtils里边创建一个 subject
Subject subject = SecurityUtils.getSubject();
//MD5加密(盐为当前用户名+666)
String s = MD5Util.encryptPassword(username, password, username + 666);
// 在认证提交前准备 token(令牌)
AuthenticationToken token=new UsernamePasswordToken(username,s);
try {
//登录
subject.login(token);
return 1;
} catch (Exception e) {
e.printStackTrace();
return 2;
}
}
}
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>商铺订单管理网站</title>
<style>
*all{
margin: 0;
padding: 0;
}
div.inner,table{
position:absolute;
}
body{
background-image:url(aaa.jpg);
background-size:100%;
}
.outer{
height: 100%;
}
.inner{
border: 5px solid rgba(255,255,255,1);
border-radius: 20px;
width: 370px;
height: 340px;
top: 40%;
left: 76%;
transform: translate(-50%,-50%);
box-shadow:11px 11px 11px rgba(50,50,50,1); ///边框阴影
}
.table{
top: 7%;
left: 12%;
//border: solid;
width: 260px;
height: 190px;
border-spacing:7px;
}
.under{
position: fixed;
left: 0px;
bottom: 30px;
width: 100%;
text-align:center;
font-size: 15px;
}
.Time{
top: 65%;
left: 62%;
position: fixed;
width: 400px;
text-align:right;
}
.TEXT{
height:72%;
width: 200px;
}
a {text-decoration: none}
</style>
</head>
<body>
<div class="outer">
<div id="showInfo"></div>
<div class="inner">
<table class="table">
<caption> <h1>订单管理系统</h1> </caption>
<tr height="30px">
<td><big><b>账 号</b></big></td>
<td><input type="text" name="username" id="username"class="TEXT"/> </td>
</tr>
<tr height="30px">
<td><big><b>密 码</b></big></td>
<td><input class="TEXT"type="password" name="password" id="password"/> </td>
</tr>
<tr height="30px">
<td colspan="2" align="right">
<input class="TEXT" type='button' id="login" value=" 登陆系统 "/>
<script><!--检查用户名 密码-->
</script>
</td>
</tr>
<tr height="20px"><td colspan="2" style="text-align:right;font-size:small"><a href = "">联系我们</a> | <a href = "">帮助中心</a> | <a href = "">其他</a></td></tr>
</table>
</div>
<script type="text/javascript">
window.onload = function(){
var btn = document.getElementById('login');
btn.onclick = function(){
var username = document.getElementById('username').value;
var password = document.getElementById('password').value;
//第一步:创建对象
var xhr = null;
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest();
}else{
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
//初始化
//准备好了
var url = './login/'+username+"/"+password;
xhr.open('get',url,false);
//这段代码在xhr.send();执行完之后才能执行
//这件事做完了怎么办
//事情办完之后干什么
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status == 200){
var data = xhr.responseText;
if(data == 2){
window.location.replace("error.html")
}else if(data == 1){
window.location.replace("success.html")
}
}
};
}
//实际的去做这件事
//去做这件事情
xhr.send(null);
}
}
</script>
<div class="under"><span>显示器分辨率要求≥1024*768,请使用Firefox浏览器(<a href="http://www.firefox.com.cn/" target="_blank">官网下载</a>),可以获得最佳显示效果,Chrome浏览器次之,IE浏览器则要求10或以上版本,其他浏览器较慢且有卡顿等现象。</span></div>
</div>
</body>
</html>