- Shiro是Apache下的一个开源的项目,我们称之为Apache Shiro ,他是一个很易用于java项目的安全框架,提供了认证。授权、加密、会话管理,于Spring Security一样都可以做一个权限的安全框架,但是与Spring Security相比,在于shiro使用了比较简单的授权方式,shiro属于轻量级的框架,相对比较Spring Security简单的多,没有Security那么复杂
- 基本的功能如下:
Authentication:身份认证/登录,验证用户是不是拥有相应的身份
Authorization:授权,即权限认证,验证某个已认证的用户是否拥有某个权限,即判断用户是否拥有访问某个资源的权限
Session Manager :会话管理,即用户登录后就是一次会话,在没有退出之前,所有信息都是保存在会话中的,会话可以是普通的javase环境的,也可以是web环境的
Cryptography:加密,保护数据的安全性
web Support:于web更好的继承
Caching:缓存,比如用户的登录,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率
Concurrency:shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去
Testing:提供测试支持
Run As:允许一个用户假装另一个用户,
Remember Me:即这次登录之后,下次访问可不用登录,记住的功能
使用Spring Boot 和 shiro权限的整合
1,使用到的依赖
<?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>
<groupId>com.troy</groupId>
<artifactId>springshiro</artifactId>
<version>1.0-SNAPSHOT</version>
<!--必备的spring boot的依赖-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
</parent>
<dependencies>
<!-- web的依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.5.6.RELEASE</version>
</dependency>
<!-- 数据库的连接,用于开启事物 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>1.5.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>1.5.6.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-Java</artifactId>
<version>5.1.9</version>
</dependency>
<!-- shiro的依赖 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.4</version>
</dependency>
</dependencies>
</project>
2,配置application.yml
server:
port: 8002
string:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/spring_shiro?
useUnicode=true&characterEncoding=UTF-8
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
jpa:
show-sql: true
hibernate:
ddl-auto: update
http:
encoding:
charset: utf-8
enabled: true
2,设置用户,角色,权限实体类
2.1 User .class 用户的实体类
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(unique = true)
private String name;
private Integer password;
@OneToMany(cascade = CascadeType.ALL,mappedBy = "user")
private List<Role> roles;
.
.
.
}
2.2角色的实体类
@Entity
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String roleName;
@ManyToOne(fetch = FetchType.EAGER)
private User user;
@OneToMany(cascade = CascadeType.ALL,mappedBy = "role")
private List<Permission> permissions;
.
.
.
}
2.3权限的实体类
@Entity
public class Permission {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String permission;
@ManyToOne(fetch = FetchType.EAGER)
private Role role;
.
.
.
}
3,认证的配置,以及过滤的条件
1,验证,以及权限的添加MyShiroRealm.class
//实现AuthorizingRealm接口用户用户认证
public class MyShiroRealm extends AuthorizingRealm{
//用于用户查询的接口
@Autowired
private ILoginService loginService;
//角色权限和对应权限添加
//PrincipalCollection 是一个身份集合,因为我们可以在shiro中同时配置多个Realm
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取登录用户名 登录的页面的数据会保存到该对象中,因为去数据库中查询
String name= (String) principalCollection.getPrimaryPrincipal();
//查询用户名称 去数据库中查询
User user = loginService.findByName(name);
//添加角色和权限 SimpleAuthorizationInfo 将添加的数据存放到该对象中,然后返回
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
//因为是一对多的关系,一个用户可以有多个角色
for (Role role:user.getRoles()) {
//添加角色
simpleAuthorizationInfo.addRole(role.getRoleName());
//每一个角色可以有多个权限
for (Permission permission:role.getPermissions()) {
//添加权限
simpleAuthorizationInfo.addStringPermission(permission.getPermission());
}
}
return simpleAuthorizationInfo;
}
//用户认证 AuthenticationToken 获取用户提交的数据
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//加这一步的目的是在Post请求的时候会先进认证,然后在到请求
if (authenticationToken.getPrincipal() == null) {
return null;
}
//获取用户信息
String name = authenticationToken.getPrincipal().toString();
User user = loginService.findByName(name);
if (user == null) {
//这里返回后会报出对应异常
return null;
} else {
//这里验证authenticationToken和simpleAuthenticationInfo的信息
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name, user.getPassword().toString(), getName());
return simpleAuthenticationInfo;
}
}
}
2,过滤配置:ShiroConfiguration.class
将之前的xml配置转换成java配置的方式
@Configuration
public class ShiroConfiguration {
//将自己的验证方式加入容器 因为自己的容器中配置了授权和认证的方法
@Bean
public MyShiroRealm myShiroRealm() {
MyShiroRealm myShiroRealm = new MyShiroRealm();
return myShiroRealm;
}
//权限管理,配置主要是Realm的管理认证
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());
return securityManager;
}
//Filter工厂,设置对应的过滤条件和跳转条件
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String,String> map = new HashMap<String, String>();
//登出
map.put("/logout","logout");
//对所有用户认证
map.put("/**","authc");
//登录
shiroFilterFactoryBean.setLoginUrl("/login");
//首页
shiroFilterFactoryBean.setSuccessUrl("/index");
//错误页面,认证不通过跳转
shiroFilterFactoryBean.setUnauthorizedUrl("/error");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
//加入注解的使用,不加入这个注解不生效
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}
3,数据层、业务层、控制层的设置
1,数据层
@NoRepositoryBean //一般不会去实例化该接口
public interface BaseRepository<T,I extends Serializable> extends PagingAndSortingRepository<T,I>,JpaSpecificationExecutor<T>{
}
2,业务层
public interface UserRepository extends BaseRepository<User,Long>{
User findByName(String name);
}
3,控制层
public interface RoleRepository extends BaseRepository<Role,Long> {
}
4,业务层的编写 -- 对用户权限的设置等
@Service
@Transactional
public class LoginServiceImpl implements ILoginService {
@Autowired
private UserRepository userRepository;
@Autowired
private RoleRepository roleRepository;
//添加用户
@Override
public User addUser(Map<String, Object> map) {
User user = new User();
user.setName(map.get("username").toString());
user.setPassword(Integer.valueOf(map.get("password").toString()));
userRepository.save(user);
return user;
}
//添加角色
@Override
public Role addRole(Map<String, Object> map) {
User user = userRepository.findOne(Long.valueOf(map.get("userId").toString()));
Role role = new Role();
role.setRoleName(map.get("roleName").toString());
role.setUser(user);
Permission permission1 = new Permission();
permission1.setPermission("create");
permission1.setRole(role);
Permission permission2 = new Permission();
permission2.setPermission("update");
permission2.setRole(role);
List<Permission> permissions = new ArrayList<Permission>();
permissions.add(permission1);
permissions.add(permission2);
role.setPermissions(permissions);
roleRepository.save(role);
return role;
}
//查询用户通过用户名
@Override
public User findByName(String name) {
return userRepository.findByName(name);
}
}
5,控制层
@RestController
public class LoginResource {
@Autowired
private ILoginService loginService;
//退出的时候是get请求,主要是用于退出
@RequestMapping(value = "/login",method = RequestMethod.GET)
public String login(){
return "login";
}
//post登录
@RequestMapping(value = "/login",method = RequestMethod.POST)
public String login(@RequestBody Map map){
//添加用户认证信息
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(
map.get("username").toString(),
map.get("password").toString());
//进行验证,这里可以捕获异常,然后返回对应信息
subject.login(usernamePasswordToken);
return "login";
}
@RequestMapping(value = "/index")
public String index(){
return "index";
}
//登出
@RequestMapping(value = "/logout")
public String logout(){
return "logout";
}
//错误页面展示
@RequestMapping(value = "/error",method = RequestMethod.POST)
public String error(){
return "error ok!";
}
//数据初始化
@RequestMapping(value = "/addUser")
public String addUser(@RequestBody Map<String,Object> map){
User user = loginService.addUser(map);
return "addUser is ok! \n" + user;
}
//角色初始化
@RequestMapping(value = "/addRole")
public String addRole(@RequestBody Map<String,Object> map){
Role role = loginService.addRole(map);
return "addRole is ok! \n" + role;
}
//注解的使用 表示访问该方法需要怎样的角色和权限
@RequiresRoles("admin")
@RequiresPermissions("create")
@RequestMapping(value = "/create")
public String create(){
return "Create success!";
}
}