简介
什么是Shiro
- Apache shiro 是一个Java的安全(权限)框架
- Shiro可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE环境,也可以用在JavaEE环境
- Shiro可以完成认证、授权、加密、会话管理、Web集成、缓存等。
官网地址:https://shiro.apache.org/
环境搭建
1.导入依赖
<!-- shiro和Spring的整合包:shiro-spring -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.8.0</version>
</dependency>
2.编写ShiroConfig配置类
package com.zjb.config;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 配置shiro总共三个部分
* 1.创建Realm对象
* 2.DefaultWebSecurityManager
* 3.ShiroFilterFactoryBean
*/
@Configuration
public class ShiroConfig {
/**
* 1.创建Realm对象,需要DIY
*/
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
/**
* 2.配置DefaultWebSecurityManager
* @return
*/
@Bean
public DefaultWebSecurityManager securityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联Realm
securityManager.setRealm(userRealm);
return securityManager;
}
/**
* 3.配置ShiroFilterFactoryBean
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(securityManager);
return bean;
}
}
3.编写UserRealm
package com.zjb.config;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
/**
* DIY的Realm extends AuthorizingRealm
*/
public class UserRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了授权=>doGetAuthorizationInfo");
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行了认证=>doGetAuthorizationInfo");
return null;
}
}
到这里基本的环境就搭建完了,运行测试。
实现登录拦截
1.添加shiro的内置过滤器
- anon:无需认证就可以访问
- authc:必须认证才可以访问
- user: 必须拥有记住我功能才能用
- role:拥有某个角色权限才能访问
- perms:拥有对某个资源的权限才能访问
/**
* 3.配置ShiroFilterFactoryBean
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(securityManager);
/**
* anon:无需认证就可以访问
* authc:必须认证才可以访问
* user: 必须拥有记住我功能才能用
* role:拥有某个角色权限才能访问
* perms:拥有对某个资源的权限才能访问
*/
Map<String, String> filterMap = new LinkedHashMap<>();
//必须登录之后才可以访问/user/* 下的所有请求
filterMap.put("/user/*","authc");
bean.setFilterChainDefinitionMap(filterMap);
//如果未登录,就跳转到登录页
bean.setLoginUrl("/toLogin");
return bean;
}
实现用户认证
1.编写UserController
package com.zjb.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/login")
public void login(String username,String password){
//获取当前用户
Subject currentUser = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
try {
//执行登录操作
currentUser.login(token);
} catch (AuthenticationException e) {
e.printStackTrace();
}
}
}
2.修改UserRealm
package com.zjb.config;
import com.zjb.po.UserPO;
import com.zjb.service.UserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
/**
* DIY的Realm extends AuthorizingRealm
*/
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
/**
* 授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了授权=>doGetAuthorizationInfo");
return null;
}
/**
* 认证
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行了认证=>doGetAuthorizationInfo");
UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
//通过用户名获取数据库用户
UserPO user = userService.getUser(token.getUsername());
//如果user==null,则说明该用户名不存在
if(user == null){
return null; //抛出UnknownAccountException异常
}
//密码认证由shiro去做
return new SimpleAuthenticationInfo("",user.getPwd(),"");
}
}
实现请求授权
1.修改ShiroConfig
/**
* 3.配置ShiroFilterFactoryBean
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(securityManager);
/**
* anon:无需认证就可以访问
* authc:必须认证才可以访问
* user: 必须拥有记住我功能才能用
* role:拥有某个角色权限才能访问
* perms:拥有对某个资源的权限才能访问
*/
Map<String, String> filterMap = new LinkedHashMap<>();
//todo 拦截
//必须登录之后才可以访问/user/* 下的所有请求
filterMap.put("/user/*","authc");
//todo 授权
//正常情况下,未授权的请求会跳转到未授权页面
filterMap.put("/user/add","perms[user:add]");
bean.setFilterChainDefinitionMap(filterMap);
//如果未登录,就跳转到登录页
bean.setLoginUrl("/toLogin");
//设置未授权请求
bean.setUnauthorizedUrl("/unAuth");
return bean;
}
2.修改UserRealm
package com.zjb.config;
import com.zjb.po.UserPO;
import com.zjb.service.UserService;
import org.apache.shiro.SecurityUtils;
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.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
/**
* DIY的Realm extends AuthorizingRealm
*/
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
/**
* 授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了授权=>doGetAuthorizationInfo");
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//获取当前用户
Subject currentUser = SecurityUtils.getSubject();
UserPO userPO = (UserPO) currentUser.getPrincipal();
//把当前用户所拥有的权限给到authorizationInfo
authorizationInfo.addStringPermission(userPO.getPerims());
return authorizationInfo;
}
/**
* 认证
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行了认证=>doGetAuthorizationInfo");
UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
//通过用户名获取数据库用户
UserPO user = userService.getUser(token.getUsername());
//如果user==null,则说明该用户名不存在
if(user == null){
return null; //抛出UnknownAccountException异常
}
//密码认证由shiro来做
//认证成功后,把用户信息给到SimpleAuthenticationInfo,用于后续授权时使用
return new SimpleAuthenticationInfo(user,user.getPwd(),"");
}
}