@RequestMapping("noauth")
@ResponseBody
public String unauthorized(){
return "未经授权无法访问此页面";
}
// perms[user:add] 必须得有 user:add 权限才可以 访问 /user/add
filterMap.put("/user/add","perms[user:add]");
// 未授权 会跳转的页面
bean.setUnauthorizedUrl("/noauth");
filterMap.put("/user/add","perms[user:add]");
:这个其实 就是 授权 最常用的监测点。就是通过授权 来判断你是否 可以访问页面!
// 授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了授权");
// 授予用户 权限
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.addStringPermission("user:add");
return simpleAuthorizationInfo;
}
这样的话,你会发现 无论你登录 哪个 用户 都会 去 赋予 授权。诶?这样不就 完蛋了吗?我们 必须 根据 用户 来 赋予给它 对应的授权呀。
perms
和 role
的呀。分析 SimpleAuthenticationInfo(Principal,user.getPwd(),realmName);
我们发现 第一个参数 是 信息主体,也就是 一个 对象。那么 我们想一下,认证登录的时候,什么玩意 是 信息的主体?答: user 对象
,整个user 对象 就是 我们 需要的信息主体。
所以我们 直接 传递 过去 就可以了。
// 认证方法那里
return new SimpleAuthenticationInfo(user,user.getPwd(),"userRealm");
然后 我们知道 SecurityUtils.getSubject(); 获取到的 subject 是独立的。所以 在授权方法那里 也是可以拿到的。
// 授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了授权");
// 拿到 当前 登录的这个对象
Subject subject = SecurityUtils.getSubject();
// 拿到 信息主体 user 这个对象,因为我们 传递 就是 user 对象
User user = (User)subject.getPrincipal();
// 授予用户 权限
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
// 添加 用户的 权限
simpleAuthorizationInfo.addStringPermission(user.getPerms());
// 添加 用户的 角色
simpleAuthorizationInfo.addRole(user.getRole());
return simpleAuthorizationInfo;
}
我们正常开发的话,权限和角色不可能是一个。而一般情况下,我们都会把多个权限和角色的字符串拼接在一起。比如说 权限A|权限B 这样的方式,然后 用 split() 分割成 一个 String 的数组即可。
其实 Shiro 整合 Thymeleaf,就是用来 做 授权控制页面渲染的
。
<dependency>
<groupId>com.github.theborakompanionigroupId>
<artifactId>thymeleaf-extras-shiroartifactId>
<version>2.1.0version>
dependency>
// 整合 shiroDialect,为了 thymeleaf 做的
@Bean
public ShiroDialect shiroDialect(){
return new ShiroDialect();
}
3. 使用 命名空间 shiro:
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h1>首页h1>
<p>[[${msg}]]p>
<hr>
<div shiro:hasPermission="user:add">
<a th:href="@{/user/add}">adda>
div>
<div shiro:hasPermission="user:update">
<a th:href="@{/user/update}">updatea>
div>
<a th:href="@{/user/logout}">注销a>
body>
html>
session
因为我们 是 DefaultWebSessionManager
也就是 WEB 项目的 管理者,所以 此时 获取到的 session 就是 httpSession。这个 不用怀疑。
我们 直接可以 在 认证 这里 进行 session 节点的添加。
// 认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行了认证");
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
User user = userService.getUserByName(token.getUsername());
if(user == null){
return null;// 这样的写法 会自动 抛出 异常 UnknowAccountException
}
// 设置一个 session 的键值对节点
Subject subject = SecurityUtils.getSubject();
Session session = subject.getSession();
session.setAttribute("loginUser",user);
// 密码认证,shiro 不让我们 开发者去做。它帮我们做。所以不用写
return new SimpleAuthenticationInfo(user,user.getPwd(),"userRealm");
}
subject.logout(); // 会自动 销毁 session
让其 没有 登陆过的,显示 登录,不显示注销。让其登陆过的,只显示 注销。
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h1>首页h1>
<p>[[${msg}]]p>
<hr>
<div th:if="${session.loginUser == null}">
<a th:href="@{/toLogin}">登录a>
div>
<div shiro:hasPermission="user:add">
<a th:href="@{/user/add}">adda>
div>
<div shiro:hasPermission="user:update">
<a th:href="@{/user/update}">updatea>
div>
<div th:if="!${session.loginUser == null}">
<a th:href="@{/user/logout}">注销a>
div>
body>
html>