demo下载地址:https://download.csdn.net/download/zhou199252/10487384
模型
假设存在用户(User)、角色(Role)、权限(Permission)3中模型。依赖关系如下:
用户分配角色,角色分配权限。用户不直接参与权限的分配。
SpringBoot集成Shiro流程
demo的代码架构如下:
创建IO模型
User存在:1、唯一ID 2、用户名 3、密码 4、拥有的Role
public class
User {
private
Integer
uid
;
private
String
username
;
private
String
password
;
private
Set
roles
=
new
HashSet<>()
;
}
Role存在:1、唯一ID 2、角色名 3、角色拥有的权限 4、拥有该角色的用户(可以不需要)
public class
Role {
private
Integer
rid
;
private
String
rname
;
private
Set
permissions
=
new
HashSet<>()
;
private
Set
users
=
new
HashSet<>()
;
}
Permission存在:1、唯一ID 2、权限名 3、。。。
public class
Permission {
private
Integer
pid
;
private
String
name
;
private
String
url
;
}
数据库sql如下:
-- 权限表 --
CREATE TABLE permission (
pid int(11) NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL DEFAULT '',
url VARCHAR(255) DEFAULT '',
PRIMARY KEY (pid)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;
INSERT INTO permission VALUES ('1', 'add', '');
INSERT INTO permission VALUES ('2', 'delete', '');
INSERT INTO permission VALUES ('3', 'edit', '');
INSERT INTO permission VALUES ('4', 'query', '');
-- 用户表 --
CREATE TABLE user(
uid int(11) NOT NULL AUTO_INCREMENT,
username VARCHAR(255) NOT NULL DEFAULT '',
password VARCHAR(255) NOT NULL DEFAULT '',
PRIMARY KEY (uid)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;
INSERT INTO user VALUES ('1', 'admin', '123');
INSERT INTO user VALUES ('2', 'demo', '123');
-- 角色表 --
CREATE TABLE role(
rid int(11) NOT NULL AUTO_INCREMENT,
rname VARCHAR(255) NOT NULL DEFAULT '',
PRIMARY KEY (rid)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;
INSERT INTO role VALUES ('1', 'admin');
INSERT INTO role VALUES ('2', 'customer');
-- 权限角色关系表 --
CREATE TABLE permission_role (
rid int(11) NOT NULL ,
pid int(11) NOT NULL ,
KEY idx_rid (rid),
KEY idx_pid (pid)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;
INSERT INTO permission_role VALUES ('1', '1');
INSERT INTO permission_role VALUES ('1', '2');
INSERT INTO permission_role VALUES ('1', '3');
INSERT INTO permission_role VALUES ('1', '4');
INSERT INTO permission_role VALUES ('2', '1');
INSERT INTO permission_role VALUES ('2', '4');
-- 用户角色关系表 --
CREATE TABLE user_role (
uid int(11) NOT NULL ,
rid int(11) NOT NULL ,
KEY idx_uid (uid),
KEY idx_rid (rid)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;
INSERT INTO user_role VALUES (1, 1);
INSERT INTO user_role VALUES (2, 2);
Mapper的配置
1、UserMapper
根据用户名去数据库查找实体
public interface
UserMapper {
User
findByUsername
(
@Param
(
"username"
) String username)
;
}
2、service配置
存在如下关系
3、mapper.xml
mapper中配置好各个IO的对应情况
需要配置读取UserMapper.xml的路径
application中需要配置需要加载的mapper类路径
授权与鉴权
需要继承
import
org.apache.shiro.realm.AuthorizingRealm
; 实现当中的方法。
1、第一个方法为授权
2、第二个方法为登陆
1、授权:
核心思想:
获取当前用户信息
因为user存放的是set,所以用for循环取出内容
取出的role存放new 出来的List中
利用for循环取出permission放入new出来的List中
将刚才的list放入 new SimpleAuthorizationInfo() 中的role和permission中
返回该对象
@Override
protected
AuthorizationInfo
doGetAuthorizationInfo
(PrincipalCollection principals)
{
//
获取
User
用户
User user = (User) principals.fromRealm(
this
.getClass().getName()).iterator().next()
;
List permissionList =
new
ArrayList<>()
;
List roleNameList =
new
ArrayList<>()
;
Set roleSet = user.getRoles()
;
if
(roleSet !=
null
)
{
for
(Role role : roleSet)
{
roleNameList.add(role.getRname())
;
Set permissionSet = role.getPermissions()
;
if
(permissionSet !=
null
)
{
for
(Permission permission : permissionSet)
{
permissionList.add(permission.getName())
;
}
}
}
}
//
需要把角色和权限放入
info
中
SimpleAuthorizationInfo info =
new
SimpleAuthorizationInfo()
;
//
权限设定
info.addStringPermissions(permissionList)
;
//
角色设定
info.addRoles(roleNameList)
;
return
info
;
}
1、登陆:
核心思想:
token中获取当前用户信息
因为user存放的是set,所以用for循环取出内容
取出用户名。用户名和密码是byte存放,可以考虑用new String转换。
返回SimpleAuthenticationInfo 对象。包括 用户实体 ,密码,该对象名
@Override
protected
AuthenticationInfo
doGetAuthenticationInfo
(AuthenticationToken token)
throws
AuthenticationException
{
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token
;
String username = usernamePasswordToken.getUsername()
;
User user =
userService
.findByUsername(username)
;
return new
SimpleAuthenticationInfo(user
,
user.getPassword()
, this
.getClass().getName())
;
}
校验重写设定
继承
SimpleCredentialsMatcher
类 重写校验方法
校验方法可以自己设定,例如:加密盐(具体需要网上看教程)
这里只是做简单的对比并且返回对比结果。
public class
CredentialMatcher
extends
SimpleCredentialsMatcher
{
@Override
public boolean
doCredentialsMatch
(AuthenticationToken token
,
AuthenticationInfo info)
{
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token
;
String password =
new
String(usernamePasswordToken.getPassword())
;
String dbPassword = (String) info.getCredentials()
;
return this
.equals(password
,
dbPassword)
;
}
}
ShiroConfiguration的配置
@Configuration
public class
ShiroConfiguration
{
@Bean
(
"shiroFilter"
)
public
ShiroFilterFactoryBean
shiroFilter
(
@Qualifier
(
"securityManager"
) SecurityManager manager)
{
ShiroFilterFactoryBean bean =
new
ShiroFilterFactoryBean()
;
bean.setSecurityManager(manager)
;
//
登陆界面
bean.setLoginUrl(
"/login"
)
;
//
成功登陆后的界面
bean.setSuccessUrl(
"/index"
)
;
//
没有权限访问的界面
bean.setUnauthorizedUrl(
"/unauthorized"
)
;
//
定制相关表单是否需要相关权限的设定,具体配置信息请看:Shiro-内置的FilterChain
LinkedHashMap
,
String> filterChainDefinitionMap =
new
LinkedHashMap<>()
;
//注意过滤器配置顺序 不能颠倒这里是按照顺序判断的
// index
界面需要鉴权
filterChainDefinitionMap.put(
"/index"
,
"authc"
)
;
// login
、
loginUser
表单不需要验证
filterChainDefinitionMap.put(
"/login"
,
"anon"
)
;
filterChainDefinitionMap.put(
"/loginUser"
,
"anon"
)
;
// admin
表单需要角色
admin
才能访问
filterChainDefinitionMap.put(
"/admin"
,
"roles[admin]"
)
;
// edit
表单需要权限
edit
才能访问
filterChainDefinitionMap.put(
"/edit"
,
"perms[edit]"
)
;
filterChainDefinitionMap.put(
"/druid/**"
,
"anon"
)
;
filterChainDefinitionMap.put(
"/**"
,
"user"
)
;
bean.setFilterChainDefinitionMap(filterChainDefinitionMap)
;
return
bean
;
}
@Bean
(
"securityManager"
)
public
SecurityManager
securityManager
(
@Qualifier
(
"authRealm"
) AuthRealm authRealm)
{
DefaultWebSecurityManager manager =
new
DefaultWebSecurityManager()
;
manager.setRealm(authRealm)
;
return
manager
;
}
@Bean
(
"authRealm"
)
public
AuthRealm
authRealm
()
{
AuthRealm authRealm =
new
AuthRealm()
;
/**
* shiro
自带的
MemoryConstrainedCacheManager
作缓存只能用于本机,那么在集群时就无法使用,
*
如果使用
ehcache
、
redis
等其他缓存,可以参考
https://www.cnblogs.com/lic309/p/4072848.html
*/
authRealm.setCacheManager(
new
MemoryConstrainedCacheManager())
;
//
用
com.mmall.demo2.CredentialMatcher
中自定义的密码比较器对密码进行比较
authRealm.setCredentialsMatcher(
new
CredentialMatcher())
;
return
authRealm
;
}
//
把
shiro
和
spring
进行绑定
@Bean
public
AuthorizationAttributeSourceAdvisor
authorizationAttributeSourceAdvisor
(
@Qualifier
(
"securityManager"
) SecurityManager securityManager)
{
AuthorizationAttributeSourceAdvisor advisor =
new
AuthorizationAttributeSourceAdvisor()
;
advisor.setSecurityManager(securityManager)
;
return
advisor
;
}
//
开启自动代码,设置为
true
即可
@Bean
public
DefaultAdvisorAutoProxyCreator
defaultAdvisorAutoProxyCreator
()
{
DefaultAdvisorAutoProxyCreator creator =
new
DefaultAdvisorAutoProxyCreator()
;
creator.setProxyTargetClass(
true
)
;
return
creator
;
}
}
其他代码展示
Controller代码
@Controller
public class
TestController
{
@RequestMapping
(
"login"
)
public
String
login
()
{
return
"login"
;
}
@RequestMapping
(
"/index"
)
public
String
index
()
{
return
"index"
;
}
@RequestMapping
(
"/logout"
)
public
String
logout
()
{
//
先验证主体
Subject subject = SecurityUtils.
getSubject
()
;
if
(subject !=
null
)
{
subject.logout()
;
}
return
"login"
;
}
@RequestMapping
(
"unauthorized"
)
public
String
unauthorized
()
{
return
"unauthorized"
;
}
@RequestMapping
(
"/admin"
)
@ResponseBody
public
String
admin
()
{
return
"admin success"
;
}
@RequestMapping
(
"/edit"
)
@ResponseBody
public
String
edit
()
{
return
"edit success"
;
}
@RequestMapping
(
"/loginUser"
)
public
String
loginUser
(
@RequestParam
(
"username"
) String username
,
@RequestParam
(
"password"
) String password
,
HttpSession session)
{
//
初始化这个用户的
token
UsernamePasswordToken token =
new
UsernamePasswordToken(username
,
password)
;
//
获取事件的主体
Subject subject = SecurityUtils.
getSubject
()
;
try
{
//
尝试登录
subject.login(token)
;
//
获取用户的全部信息
User user = (User) subject.getPrincipal()
;
//
用于界面输出
session.setAttribute(
"user"
,
user)
;
return
"index"
;
}
catch
(Exception e)
{
return
"login"
;
}
}
}
application.properties代码
##蓝色加粗字体需自行修改
## database ##
spring.datasource.type
=
com
.
alibaba
.
druid
.
pool
.
DruidDataSource
spring.datasource.driver-class-name
=
com
.
mysql
.
jdbc
.
Driver
spring.datasource.url
=
jdbc:mysql://localhost:3306/
fys
?characterEncoding=UTF-8
spring.datasource.username
=
root
spring.datasource.password
=
root
## mybatis ##
mybatis.mapper-locations
=
mappers/*.xml
#mybatis.type-aliases-package=com.mmall.demo2.model
## jsp ##
spring.mvc.view.prefix
=
/pages/
spring.mvc.view.suffix
=
.jsp
index.jsp
<%@
page
contentType="
text/html;charset=UTF-8
" language="
java
" %>
Home
欢迎登录
,
${
user.username
}
login.jsp
<%@
page
contentType="
text/html;charset=UTF-8
" language="
java
" %>
Login
欢迎登录
type=
"text"
name=
"username"
>
type=
"password"
name=
"password"
>
type=
"submit"
value=
"
提交
"
>
unauthorized.jsp
<%@
page
contentType="
text/html;charset=UTF-8
" language="
java
" %>
Unauthorized
Unauthorized!
FilerChain的方法解释:
/**
* Shiro-1.2.2内置的FilterChain
* @see =============================================================================================================================
* @see 1)Shiro验证URL时,URL匹配成功便不再继续匹配查找(所以要注意配置文件中的URL顺序,尤其在使用通配符时)
* @see 故filterChainDefinitions的配置顺序为自上而下,以最上面的为准
* @see 2)当运行一个Web应用程序时,Shiro将会创建一些有用的默认Filter实例,并自动地在[main]项中将它们置为可用
* @see 自动地可用的默认的Filter实例是被DefaultFilter枚举类定义的,枚举的名称字段就是可供配置的名称
* @see anon---------------org.apache.shiro.web.filter.authc.AnonymousFilter
* @see authc--------------org.apache.shiro.web.filter.authc.FormAuthenticationFilter
* @see authcBasic---------org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
* @see logout-------------org.apache.shiro.web.filter.authc.LogoutFilter
* @see noSessionCreation--org.apache.shiro.web.filter.session.NoSessionCreationFilter
* @see perms--------------org.apache.shiro.web.filter.authz.PermissionAuthorizationFilter
* @see port---------------org.apache.shiro.web.filter.authz.PortFilter
* @see rest---------------org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
* @see roles--------------org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
* @see ssl----------------org.apache.shiro.web.filter.authz.SslFilter
* @see user---------------org.apache.shiro.web.filter.authz.UserFilter
* @see =============================================================================================================================
* @see 3)通常可将这些过滤器分为两组
* @see anon,authc,authcBasic,user是第一组认证过滤器
* @see perms,port,rest,roles,ssl是第二组授权过滤器
* @see 注意user和authc不同:当应用开启了rememberMe时,用户下次访问时可以是一个user,但绝不会是authc,因为authc是需要重新认证的
* @see user表示用户不一定已通过认证,只要曾被Shiro记住过登录状态的用户就可以正常发起请求,比如rememberMe
* @see 说白了,以前的一个用户登录时开启了rememberMe,然后他关闭浏览器,下次再访问时他就是一个user,而不会authc
* @see =============================================================================================================================
* @see 4)举几个例子
* @see /admin=authc,roles[admin] 表示用户必需已通过认证,并拥有admin角色才可以正常发起'/admin'请求
* @see /edit=authc,perms[admin:edit] 表示用户必需已通过认证,并拥有admin:edit权限才可以正常发起'/edit'请求
* @see /home=user 表示用户不一定需要已经通过认证,只需要曾经被Shiro记住过登录状态就可以正常发起'/home'请求
* @see =============================================================================================================================
* @see 5)各默认过滤器常用如下(注意URL Pattern里用到的是两颗星,这样才能实现任意层次的全匹配)
* @see /admins/**=anon 无参,表示可匿名使用,可以理解为匿名用户或游客
* @see /admins/user/**=authc 无参,表示需认证才能使用
* @see /admins/user/**=authcBasic 无参,表示httpBasic认证
* @see /admins/user/**=user 无参,表示必须存在用户,当登入操作时不做检查
* @see /admins/user/**=ssl 无参,表示安全的URL请求,协议为https
* @see /admins/user/**=perms[user:add:*]
* @see 参数可写多个,多参时必须加上引号,且参数之间用逗号分割,如/admins/user/**=perms["user:add:*,user:modify:*"]
* @see 当有多个参数时必须每个参数都通过才算通过,相当于isPermitedAll()方法
* @see /admins/user/**=port[8081]
* @see 当请求的URL端口不是8081时,跳转到schemal://serverName:8081?queryString
* @see 其中schmal是协议http或https等,serverName是你访问的Host,8081是Port端口,queryString是你访问的URL里的?后面的参数
* @see /admins/user/**=rest[user]
* @see 根据请求的方法,相当于/admins/user/**=perms[user:method],其中method为post,get,delete等
* @see /admins/user/**=roles[admin]
* @see 参数可写多个,多个时必须加上引号,且参数之间用逗号分割,如/admins/user/**=roles["admin,guest"]
* @see 当有多个参数时必须每个参数都通过才算通过,相当于hasAllRoles()方法
* @see =============================================================================================================================
* @create Sep 29, 2013 5:24:49 PM
* @author 玄玉
*/
我截取一段关于shiro.xml中关于
ShiroFilterFactoryBean配置的
说明,如下:
securityManager:这个属性是必须的。
loginUrl:没有登录的用户请求需要登录的页面时自动跳转到登录页面,不是必须的属性,不输入地址的话会自动寻找项目web项目的根目录下的”/login.jsp”页面。
successUrl:登录成功默认跳转页面,不配置则跳转至”/”。如果登陆前点击的一个需要登录的页面,则在登录自动跳转到那个需要登录的页面。不跳转到此。
unauthorizedUrl:没有权限默认跳转的页面。
过滤器简称
对应的java类
anon
org.apache.shiro.web.filter.authc.AnonymousFilter
authc
org.apache.shiro.web.filter.authc.FormAuthenticationFilter
authcBasic
org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
perms
org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
port
org.apache.shiro.web.filter.authz.PortFilter
rest
org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
roles
org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
ssl
org.apache.shiro.web.filter.authz.SslFilter
user
org.apache.shiro.web.filter.authc.UserFilter
logout
org.apache.shiro.web.filter.authc.LogoutFilter
anon:例子/admins/**=anon 没有参数,表示可以匿名使用。
authc:例如/admins/user/**=authc表示需要认证(登录)才能使用,没有参数
roles:例子/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如admins/user/**=roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。
perms:例子/admins/user/**=perms[user:add:*],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。
rest:例子/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method] ,其中method为post,get,delete等。
port:例子/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString
是你访问的url里的?后面的参数。
authcBasic:例如/admins/user/**=authcBasic没有参数表示httpBasic认证
ssl:例子/admins/user/**=ssl没有参数,表示安全的url请求,协议为https
user:例如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查
注:anon,authcBasic,auchc,user是认证过滤器,
perms,roles,ssl,rest,port是授权过滤器