1.log4j文件编写
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n
# General Apache libraries
log4j.logger.org.apache=WARN
# Spring
log4j.logger.org.springframework=WARN
# Default Shiro logging
log4j.logger.org.apache.shiro=INFO
# Disable verbose logging
log4j.logger.org.apache.shiro.util.ThreadContext=WARN
log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN
2.shiro中的常用方法
//获得subject
Subject currentUser = SecurityUtils.getSubject();
//获得session
Session session = currentUser.getSession();
//判断当前用户是否认证
currentUser.isAuthenticated()
//获得当前用户的认证
currentUser.getPrincipal()
//用户是否拥有什么角色
currentUser.hasRole("schwartz")
//用户是否拥有什么权限
currentUser.isPermitted("lightsaber:wield")
//注销
currentUser.logout();
3.SpirngBoot整合shiro环境
1.引入依赖
<!--shiro整合spring-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.8.0</version>
</dependency>
2.创建UserRealm类继承AuthorizingRealm
package com.wxk.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;
//自定义的UserRealm
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;
}
}
3.创建shiro的配置类
package com.wxk.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;
@Configuration
public class ShiroConfig {
//1.创建realm对象,需要自定义
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
//2.DefaultWebSecurityManager
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm){
DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
//关联realm
securityManager.setRealm(userRealm);
return securityManager;
}
//3.ShiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
return bean;
}
}
4.shiro实现登陆拦截
在ShiroFilterFactoryBean 类中进行拦截以及被拦截时跳转的网页
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
/*
* anon:无需认证就可以使用
* authc:必须认证了才可以使用
* user:必须拥有 记住我 功能才能使用
* perms:拥有对某个资源的权限才能访问
* role:拥有某个角色权限才能访问
* */
Map<String,String> filterMap=new LinkedHashMap<>();
filterMap.put("/user/add","authc");
filterMap.put("/user/update","authc");
bean.setFilterChainDefinitionMap(filterMap);
//设置登陆的请求
bean.setLoginUrl("/toLogin");
return bean;
}
5.shiro实现认证
首先有一个前提,设置了部分网页只有认证了才可以使用,否则就跳转到登陆页面
filterMap.put("/user/add","authc");
filterMap.put("/user/update","authc");
bean.setLoginUrl("/toLogin");
在登陆页面对应的控制器中进行如下设置
@RequestMapping("/login")
public String login(String username,String password,Model model){
//获取当前用户
Subject subject = SecurityUtils.getSubject();
//封装用户的登陆数据
UsernamePasswordToken token=new UsernamePasswordToken(username,password);
try {
//执行登陆的方法,没有异常说明登陆成功
subject.login(token);
return "index";
}catch (UnknownAccountException e){//用户名不存在
model.addAttribute("msg","用户名错误");
return "login";
}catch (IncorrectCredentialsException e){//密码错误
model.addAttribute("msg","密码错误");
return "login";
}
}
然后subject.login会跳转到你配置Realm对象中
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行了=》认证doGetAuthorizationInfo");
//用户名,密码等 在数据库中取
String name="root";
String password="123456";
UsernamePasswordToken userToken = (UsernamePasswordToken) token;
if(!userToken.getUsername().equals(name)){
return null;//抛出异常, UnknownAccountException
}
//密码认证,由shiro来帮你做
return new SimpleAuthenticationInfo("",password,"");
}
6.shiro实现授权
在实际开发中,一些功能可能需要这个账号拥有某些权限才能执行,这个时候就需要对账户进行授权,在授权之前,需要先对某些访问进行权限的限制
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
/*
* anon:无需认证就可以使用
* authc:必须认证了才可以使用
* user:必须拥有 记住我 功能才能使用
* perms:拥有对某个资源的权限才能访问
* role:拥有某个角色权限才能访问
* */
Map<String,String> filterMap=new LinkedHashMap<>();
filterMap.put("/user/add","perms[user:add]");
bean.setFilterChainDefinitionMap(filterMap);
//设置登陆的请求
bean.setLoginUrl("/toLogin");
return bean;
}
例如上述这个例子,如果对add的请求进行访问,那么就需要该账户拥有一个user:add的权限,因此我们可以在realm类中进行授权
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了=》授权doGetAuthorizationInfo");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermission("user:add");
return info;
}
这样用户就拥有了user:add
的权限,但是这样会导致所有的用户都拥有user:add的权限,那这个拦截就没有必要了,显然是不科学的,这个时候可以在realm类的认证方法中,返回一个值,这个值是我们在数据库中查询得到的这个账户拥有的权限。
return new SimpleAuthenticationInfo(user,user.getPassword(),"");
其中user就是可以传到subject进行保存的
当我们要使用时,利用下列方法取出即可
//拿到当前登陆的这个对象
Subject subject= SecurityUtils.getSubject();
User user= (User) subject.getPrincipal();