SpringBoot整合shiro框架
1.引入依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.7.0</version>
</dependency>
yml文件中配置拦截后默认访问首页
shiro:
loginUrl: /login.html
2.创建realm对象,并在此类型的对象中定义认证和授权数据的获取逻辑
2.1.获取认证信息并封装
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
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.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Set;
public class ShiroRealm extends AuthorizingRealm {
@Autowired
SysUsersDao sysUsersDao;
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken uToken=(UsernamePasswordToken)authenticationToken;
String name = uToken.getUsername();
SysUsers sysUsers = sysUsersDao.selectUserByUsername(name);
if(sysUsers==null)throw new UnknownAccountException();
if(sysUsers.getValid()==0)throw new LockedAccountException();
ByteSource credentialsSalt = ByteSource.Util.bytes(sysUsers.getSalt());
SimpleAuthenticationInfo info =
new SimpleAuthenticationInfo(
sysUsers,
sysUsers.getPassword(),
credentialsSalt,
this.getName()
);
return info;
}
}
2.2 获取凭证匹配器
@Override
public CredentialsMatcher getCredentialsMatcher( ) {
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("MD5");
matcher.setHashIterations(1);
return matcher;
}
2.3 获取授权信息并封装(认证功能测试完毕再实现此操作)
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
SysUsers user= (SysUsers) principalCollection.getPrimaryPrincipal();
Set<String> set= sysMenuDao.selectUserPermissions(user.getId());
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
info.setStringPermissions(set);
return info;
}
3.创建shiro配置类
3.1返回刚刚自己创建的Realm对象
@Configuration
public class MyShiroConfig {
@Bean
public Realm realm(){
return new ShiroRealm();
}
}
anon,logout,authc,user…这些是shiro框架指定的过滤规则
(“/test1/**”, “anon”) anon 放行资源
(“/test1/logout”,“logout”) logout 拦截进入退出页面
(“/**”, “authc”); authc 对没有登录的用户拦截
(设置记住我功能后 这里的authc改为user)
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition(){
DefaultShiroFilterChainDefinition chainDefinition=
new DefaultShiroFilterChainDefinition();
chainDefinition.addPathDefinition("/test1/**", "anon");
chainDefinition.addPathDefinition("/test1/logout","logout");
chainDefinition.addPathDefinition("/**", "user");
return chainDefinition;
}
3.3 记住用户功能
不配置setCipherKey是默认自己生成密钥对用户信息进行加密解密,这样的话你使用"记住我"时当你服务器重启就会再次重新生成密钥,用新的密钥解密之前cookie中的密钥就会报错无法解密
@Bean
public RememberMeManager rememberMeManager(){
CookieRememberMeManager cManager=new CookieRememberMeManager();
SimpleCookie cookie=new SimpleCookie("rememberCGB");
cookie.setMaxAge(7*24*60*60);
cManager.setCookie(cookie);
cManager.setCipherKey(Base64.decode("6ZmI612j51+R5aSn5201AA=="));
return cManager;
}
3.4 配置session管理器对象
@Bean
public SessionManager sessionManager(){
DefaultWebSessionManager sessionManager=new DefaultWebSessionManager();
sessionManager.setGlobalSessionTimeout(2*60*1000);
sessionManager.setDeleteInvalidSessions(true);
sessionManager.setSessionIdUrlRewritingEnabled(false);
return sessionManager;
}
3.5 解决@RequiresPermissions用在controller层导致@GetMapper.@PostMapper…等注解失效的问题
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator proxyCreator=new DefaultAdvisorAutoProxyCreator();
proxyCreator.setProxyTargetClass(true);
return proxyCreator;
}
4.测试认证授权功能
4.1 认证功能
JsonResult是自己封装的类,用于服务端响应到客户端的数据(文章最后有添加这个类的代码)
@GetMapping("/{username}/{password}")
public JsonResult doUpdatePassword(@PathVariable String username,
@PathVariable String password){
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token =
new UsernamePasswordToken(username, password);
token.setRememberMe(true);
subject.login(token);
return new JsonResult("登录 ok");
}
4.2 授权功能
为service方法加@RequiresPermissions(“sys:user:update”)
"sys:user:update"为shiro授权信息的固定格式
@RequiresPermissions("sys:user:update")
public int validById(Integer id, Integer valid) {
int rows=sysUserDao.validById(id,valid,"admin");
if(rows==0)
throw new RestClientException("记录可能不存在了");
return rows;
}
5.配置全局异常处理
@RestControllerAdvice(annotations = RestController.class)
public class RestControllerExceptionHandler {
public static final Logger log =
LoggerFactory.getLogger(RestControllerExceptionHandler.class);
@ExceptionHandler(RuntimeException.class)
public JsonResult bdoHandleRuntimeException(RuntimeException e) {
e.printStackTrace();
log.error("exception msg is {}",e.getMessage());
return new JsonResult(e);
}
public JsonResult doShiroException(ShiroException e){
e.printStackTrace();
JsonResult r=new JsonResult();
r.setState(0);
if (e instanceof UnknownAccountException){
r.setMessage("账户不存在");
}else if (e instanceof IncorrectCredentialsException){
r.setMessage("密码不正确");
}else if (e instanceof LockedAccountException){
r.setMessage("账户被锁定");
}else if (e instanceof AuthorizationException){
r.setMessage("没有权限");
}else{
r.setMessage("认证或授权失败");
}
return r;
}
}
JsonResult代码
public class JsonResult {
private Integer state=1;
private String message="ok";
private Object data;
public JsonResult(){}
public JsonResult(String message){
this.message=message;
}
public JsonResult(Integer state, String message){
this(message);
this.state=state;
}
public JsonResult(Object data){
this.data=data;
}
public JsonResult(Throwable exception){
this(0,exception.getMessage());
}
public Integer getState() {
return state;
}
public void setState(Integer state) {
this.state = state;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}