一、概述
1.1 什么是Shiro
Apache Shiro是一个功能强大、简单易用的Java安全框架,提供了认证、授权、加密和会话管理等功能。
官方网址:http://shiro.apache.org/
(1)认证
用户身份识别,常被称为用户“登录”,判断用户是否登陆,如果未登陆则拦截其请求。
(2)授权
访问控制;当用户登陆后,判断其身份是否有权限访问相应的资源,如果没有权限则拦截。
1.2 Shiro框架组成
Subject:主体,可以是任意对象。在Web应用中,一般使用当前登录用户作为主体。如果主体要访问系统,那么Shiro就会对主体进行认证、授权等工作。
SecurityManager:执行了主体的认证、授权工作、会话管理、缓存管理等工作。
Authenticator:负责执行认证操作。
Authorizer:负责执行授权操作。
SessionManager:负责对session进行管理;
Session DAO: 负责管理session数据。一般来说,如果需要针对个性化的Session数据存储,才需要使用Session DAO;
CacheManager:负责对Session和授权数据进行缓存;
Realm:相当于数据源,通过该Realm存取认证、授权相关的数据;
1.3 过滤器
Shiro是以过滤器的方式对访问规则进行控制,并内置一组过滤器。其中比较常用的是:
anon:不认证也可以访问;
authc:必须认证后才允许访问;
perms:指定资源需要有指定权限才允许访问;
二,Shiro认证
第一步:构建SecurityManager环境
//构建SecurityManager环境
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
//设置数据源
defaultSecurityManager.setRealm(simpleAccountRealm);
第二步: 主体提交认证请求
//主体提交认证请求
SecurityUtils.setSecurityManager(defaultSecurityManager);
Subject subject = SecurityUtils.getSubject();
登录测试举例:
package com.lmc.test;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.SimpleAccount;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Before;
import org.junit.Test;
/**
* @Author lmc
* @Description
* @Date: Create in 17:27 2019/10/27
*/
public class ShiroTest {
SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();
@Before
public void addUser(){
simpleAccountRealm.addAccount("lmc", "111");
}
@Test
public void testAuthentication(){
//构建SecurityManager环境
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
//设置数据源
defaultSecurityManager.setRealm(simpleAccountRealm);
//主体提交认证请求
SecurityUtils.setSecurityManager(defaultSecurityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("lmc", "111");
//登录
subject.login(token);
//获取登录名
System.out.println(subject.getPrincipal());
System.out.println("isAuthenticated : " + subject.isAuthenticated());
//注销
subject.logout();
System.out.println("isAuthenticated : " + subject.isAuthenticated());
}
}
二,Shiro授权
- 创建SecurityManager
- 进行主体授权
- 主体授权交给SecurityManager授权
- Authorizer授权
- Realm获取角色权限数据
测试举例:
package com.lmc.test;
import com.lmc.beans.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.SimpleAccount;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Before;
import org.junit.Test;
/**
* @Author lmc
* @Description
* @Date: Create in 17:27 2019/10/27
*/
public class ShiroTest {
SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();
@Before
public void addUser(){
//给角色授权(一个或多个)
//simpleAccountRealm.addAccount("lmc", "111", "admin");
simpleAccountRealm.addAccount("lmc", "111", "admin", "user");
}
@Test
public void testAuthentication(){
//构建SecurityManager环境
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
//设置数据源
defaultSecurityManager.setRealm(simpleAccountRealm);
//主体提交认证请求
SecurityUtils.setSecurityManager(defaultSecurityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("lmc", "111");
//登录
subject.login(token);
System.out.println("isAuthenticated : " + subject.isAuthenticated());
//检查用户是否具有admin权限(一个或多个)
//subject.checkRole("admin");
subject.checkRoles("admin", "user");
}
}
三, Realm
3.1 iniRealm
测试资源文件 user.ini:
[users]
lmc=111,admin
[roles]
admin=user:delete,user:update
测试举例:
package com.lmc.test;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Before;
import org.junit.Test;
/**
* @Author lmc
* @Description
* @Date: Create in 18:05 2019/10/27
*/
public class InitRealmTest {
@Test
public void testAuthentication(){
//创建initRealm对象
IniRealm iniRealm = new IniRealm("classpath:user.ini");
//构建SecurityManager环境
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
defaultSecurityManager.setRealm(iniRealm);
//主体提交认证请求
SecurityUtils.setSecurityManager(defaultSecurityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("lmc", "111");
//登录
subject.login(token);
System.out.println("isAuthenticated : " + subject.isAuthenticated());
//获取登录名
System.out.println(subject.getPrincipal());
//检查是否有该角色
subject.checkRole("admin");
//检查是否有该权限
subject.checkPermission("user:update");
}
}
3.2 jdbcRealm
第一步: 导入相关依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.41</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.9</version>
</dependency>
第二步: 创建数据源
DruidDataSource dataSource = new DruidDataSource();
{
dataSource.setUrl("jdbc:mysql://localhost:3306/mblog?serverTimezone=GMT%2B8");
dataSource.setUsername("root");
dataSource.setPassword("root");
}
测试举例:
package com.lmc.test;
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Test;
/**
* @Author lmc
* @Description
* @Date: Create in 18:20 2019/10/27
*/
public class JdbcRealmTest {
DruidDataSource dataSource = new DruidDataSource();
{
dataSource.setUrl("jdbc:mysql://localhost:3306/mblog?serverTimezone=GMT%2B8");
dataSource.setUsername("root");
dataSource.setPassword("root");
}
@Test
public void testAuthentication() {
//创建jdbcRealm对象
JdbcRealm jdbcRealm = new JdbcRealm();
jdbcRealm.setDataSource(dataSource);
//使用自定义SQL语句
String sql = "select password from user where username = ?";
jdbcRealm.setAuthenticationQuery(sql);
//权限开关,默认为false
jdbcRealm.setPermissionsLookupEnabled(true);
//构建SecurityManager环境
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
defaultSecurityManager.setRealm(jdbcRealm);
//主体提交认证请求
SecurityUtils.setSecurityManager(defaultSecurityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("lmc", "111");
//登录
subject.login(token);
System.out.println("isAuthenticated : " + subject.isAuthenticated());
//获取登录名
System.out.println(subject.getPrincipal());
subject.checkRoles("admin", "user");
subject.checkPermission("user:delete");
}
}
注意:
- 默认情况下jdbcrealm不会开启权限,要自己手动开启
//权限开关,默认为false
jdbcRealm.setPermissionsLookupEnabled(true);
- 默认情况下数据库需要有users, user_roles, roles_permissions表, 如果要自定义表,可以自己修改:
JdbcRealm jdbcRealm = new JdbcRealm();
//使用自定义SQL语句
String sql = "select password from user where username = ?";
jdbcRealm.setAuthenticationQuery(sql);
3.3 自定义Realm
第一步: 定义一个自定义Realm, 继承 AuthorizingRealm
package com.lmc.shiro.realm;
import com.lmc.shiro.beans.User;
import com.lmc.shiro.service.UserService;
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 org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @Author lmc
* @Description
* @Date: Create in 11:46 2019/10/27
*/
@Component("userRealm")
public class UserRealm extends AuthorizingRealm {
/**
* 授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null ;
}
/**
* 认证
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
return null;
}
}
第二步: 认证, 重写 AuthenticationInfo 方法
/**
* 认证
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//1.得到令牌
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
//2.调用业务组件进行登录判断
User user = new User();
user.setUsername(token.getUsername());
// user.setPassword(new String(token.getPassword()));
System.out.println("lmchh = " + token.getUsername());
UserService userService = new UserService();
List<User> users = userService.find((String) authenticationToken.getPrincipal());
//3.判断用户是否为空,如果不为空代表登录成功
if (users != null) {
/*
参数1:主角(用户对象)
参数2:密码
参数3:realm的类名
*/
user = users.get(0);
return new SimpleAuthenticationInfo(user, user.getPassword(), user.getUsername());
}
return null;
}
第三步: 授权, 重写 doGetAuthorizationInfo 方法
/**
* 授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
User user = (User) principalCollection.getPrimaryPrincipal();
//模拟从数据库或缓存中获取角色数据
Set<String> roles = getRolesByUsername(user.getUsername());
//模拟从数据库或缓存中获取权限数据
Set<String> permissions = getPermissionsByUsername(user.getUsername());
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.setRoles(roles);
simpleAuthorizationInfo.setStringPermissions(permissions);
return simpleAuthorizationInfo ;
}
源文件:
package com.lmc.shiro.realm;
import com.lmc.shiro.beans.User;
import com.lmc.shiro.service.UserService;
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 org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @Author lmc
* @Description
* @Date: Create in 11:46 2019/10/27
*/
@Component("userRealm")
public class UserRealm extends AuthorizingRealm {
/**
* 授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
User user = (User) principalCollection.getPrimaryPrincipal();
//模拟从数据库或缓存中获取角色数据
Set<String> roles = getRolesByUsername(user.getUsername());
//模拟从数据库或缓存中获取权限数据
Set<String> permissions = getPermissionsByUsername(user.getUsername());
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.setRoles(roles);
simpleAuthorizationInfo.setStringPermissions(permissions);
return simpleAuthorizationInfo ;
}
/**
* 认证
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//1.得到令牌
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
//2.调用业务组件进行登录判断
User user = new User();
user.setUsername(token.getUsername());
// user.setPassword(new String(token.getPassword()));
System.out.println("lmchh = " + token.getUsername());
UserService userService = new UserService();
List<User> users = userService.find((String) authenticationToken.getPrincipal());
//3.判断用户是否为空,如果不为空代表登录成功
if (users != null) {
/*
参数1:主角(用户对象)
参数2:密码
参数3:realm的类名
*/
user = users.get(0);
return new SimpleAuthenticationInfo(user, user.getPassword(), user.getUsername());
}
return null;
}
private Set<String> getPermissionsByUsername(String username) {
Set<String> sets = new HashSet<>();
sets.add("user:select");
sets.add("user:update");
return sets;
}
private Set<String> getRolesByUsername(String username) {
Set<String> sets = new HashSet<>();
sets.add("admin");
sets.add("user");
return sets;
}
}
第三步: 编写测试类
package com.lmc.test;
import com.lmc.shiro.realm.UserRealm;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Test;
/**
* @Author lmc
* @Description
* @Date: Create in 21:28 2019/10/27
*/
public class UserRealmTest {
@Test
public void testAuthentication() {
UserRealm userRealm = new UserRealm();
//构建SecurityManager环境
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
defaultSecurityManager.setRealm(userRealm);
//主体提交认证请求
SecurityUtils.setSecurityManager(defaultSecurityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("lmc", "111");
//登录
subject.login(token);
System.out.println("isAuthenticated : " + subject.isAuthenticated());
//获取登录名
System.out.println(subject.getPrincipal());
subject.checkRole("admin");
subject.checkPermission("user:update");
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/81657.html