|
基本步骤:
- 添加pom文件依赖
- 书写自定义的realm
- 配置shiro
- 控制层使用
项目目录结构:

1.添加pom文件依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
2.书写自定义realm
package com.ahut.shiro;
import java.util.ArrayList;
import java.util.List;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
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;
/**
*
* @ClassName: MyRealm
* @Description: 自定义realm
* @author cheng
* @date 2017年10月9日 上午10:54:00
*/
public class MyRealm extends AuthorizingRealm {
/**
* 用于认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("使用了自定义的realm,用户认证...");
System.out.println("用户名:" + ((UsernamePasswordToken) token).getUsername());
System.out.println("密码:" + new String(((UsernamePasswordToken) token).getPassword()));
String userName = (String) token.getPrincipal();
String password = "36f2dfa24d0a9fa97276abbe13e596fc";
String salt = "qwerty";
return new SimpleAuthenticationInfo(userName, password, ByteSource.Util.bytes(salt), this.getName());
}
/**
* 用于授权
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("使用了自定义的realm,用户授权...");
List<String> roles = new ArrayList<>();
roles.add("admin");
roles.add("user");
List<String> permissions = new ArrayList<>();
permissions.add("admin:select");
permissions.add("admin:delete");
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.addStringPermissions(permissions);
simpleAuthorizationInfo.addRoles(roles);
return simpleAuthorizationInfo;
}
}
3.配置shiro
package com.ahut.config;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.ahut.shiro.MyRealm;
/**
*
* @ClassName: ShiroConfig
* @Description: spring整合shiro配置
* @author cheng
* @date 2017年10月10日 上午9:46:43
*/
@Configuration
public class ShiroConfig {
/**
*
* @Title: createMyRealm
* @Description: 自定义的realm
* @return
*/
@Bean
public MyRealm createMyRealm() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5");
hashedCredentialsMatcher.setHashIterations(2);
MyRealm myRealm = new MyRealm();
myRealm.setCredentialsMatcher(hashedCredentialsMatcher);
return myRealm;
}
/**
*
* @Title: securityManager
* @Description: 注入自定义的realm
* @Description: 注意方法返回值SecurityManager为org.apache.shiro.mgt.SecurityManager
* ,不要导错包
* @return
*/
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(createMyRealm());
return securityManager;
}
/**
*
* @Title: shirFilter
* @Description: Shiro 的Web过滤器
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setLoginUrl("/userLogin");
shiroFilterFactoryBean.setSuccessUrl("/index");
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap.put("/logout", "logout");
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
}
代码说明:
1.自定义的realm和注入自定义的realm相当于以前的shiro.ini文件
#自定义的realm
myRealm=com.ahut.test.MyRealm
# 注入自定义的realm
securityManager.realms=$myRealm
2.ShiroFilterFactoryBean相当于以下xml配置
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/login.action" />
<property name="successUrl" value="/first.action"/>
<property name="unauthorizedUrl" value="/refuse.jsp" />
<property name="filters">
<map>
<entry key="authc" value-ref="formAuthenticationFilter" />
</map>
</property>
<property name="filterChainDefinitions">
<value>
/images/** = anon
/js/** = anon
/styles/** = anon
/validatecode.jsp = anon
/logout.action = logout
/index.jsp = user
/first.action = user
/welcome.jsp = user
/** = authc
</value>
</property>
</bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="customRealm" />
<property name="cacheManager" ref="cacheManager"/>
<property name="sessionManager" ref="sessionManager" />
<property name="rememberMeManager" ref="rememberMeManager"/>
</bean>
<bean id="customRealm" class="cn.itcast.ssm.shiro.CustomRealm">
<property name="credentialsMatcher" ref="credentialsMatcher"/>
</bean>
<bean id="credentialsMatcher"
class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="md5" />
<property name="hashIterations" value="1" />
</bean>
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:shiro-ehcache.xml"/>
</bean>
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<property name="globalSessionTimeout" value="600000"/>
<property name="deleteInvalidSessions" value="true"/>
</bean>
<bean id="formAuthenticationFilter"
class="cn.itcast.ssm.shiro.CustomFormAuthenticationFilter ">
<property name="usernameParam" value="username" />
<property name="passwordParam" value="password" />
<property name="rememberMeParam" value="rememberMe"/>
</bean>
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
<property name="cookie" ref="rememberMeCookie" />
</bean>
<bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg value="rememberMe" />
<property name="maxAge" value="2592000" />
</bean>
4.控制层使用
package com.ahut.action
import java.util.Map
import javax.servlet.http.HttpServletRequest
import org.apache.shiro.SecurityUtils
import org.apache.shiro.authc.DisabledAccountException
import org.apache.shiro.authc.ExcessiveAttemptsException
import org.apache.shiro.authc.ExpiredCredentialsException
import org.apache.shiro.authc.IncorrectCredentialsException
import org.apache.shiro.authc.LockedAccountException
import org.apache.shiro.authc.UnknownAccountException
import org.apache.shiro.authc.UsernamePasswordToken
import org.apache.shiro.subject.Subject
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
@RestController
public class ShiroAction {
@RequestMapping(value = "/userLogin")
public String userLogin(String username, String password) {
// 以下部分在配置阶段就已经完成,可以直接使用
// 读取配置文件
// Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini")
// 获取SecurityManager的实例
// SecurityManager securityManager = factory.getInstance()
// 把 securityManager 的实例绑定到 SecurityUtils 上
// SecurityUtils.setSecurityManager(securityManager)
System.out.println(username + ":" + password)
Subject subject = SecurityUtils.getSubject()
// 自己创建一个令牌,输入用户名和密码
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password)
try {
subject.login(usernamePasswordToken)
System.out.println("身份认证成功!")
} catch (UnknownAccountException e) {
e.printStackTrace()
System.out.println("账号不存在!")
} catch (LockedAccountException e) {
e.printStackTrace()
System.out.println("账号被锁定!")
} catch (DisabledAccountException e) {
e.printStackTrace()
System.out.println("账号被禁用!")
} catch (IncorrectCredentialsException e) {
e.printStackTrace()
System.out.println("凭证/密码错误!")
} catch (ExpiredCredentialsException e) {
e.printStackTrace()
System.out.println("凭证/密码过期!")
} catch (ExcessiveAttemptsException e) {
e.printStackTrace()
System.out.println("登录失败次数过多!")
}
// 是否认证通过
boolean isAuthenticated1 = subject.isAuthenticated()
System.out.println("登录后,是否认证通过:" + isAuthenticated1)
// 退出
subject.logout()
// 是否认证通过
boolean isAuthenticated2 = subject.isAuthenticated()
System.out.println("退出登录后,是否认证通过:" + isAuthenticated2)
return "处理登录"
}
}
可能出现的问题
页面加载css或者js时,出现以下错误:Resource interpreted as Stylesheet but transferred with MIME type text/html
原因:shiro配置原因,对需要认证的资源进行了拦截操作
// authc:所有url都必须认证通过才可以访问
filterChainDefinitionMap.put("/**", "authc")
修改以上代码为:
filterChainDefinitionMap.put("/**", "anon")
完整代码:
/**
* @description: shiro web过滤器
* @author cheng
* @dateTime 2018/4/18 15:50
*/
@Bean
public ShiroFilterFactoryBean createShiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setLoginUrl("/v1/toLoginPage");
Map<String, String> filterChainDefinitionMap = new HashMap<>();
filterChainDefinitionMap.put("/v1/users/", "anon");
filterChainDefinitionMap.put("/v1/toLoginPage", "anon");
filterChainDefinitionMap.put("/v1/login", "anon");
filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap.put("/**", "anon");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
|