public Object around(ProceedJoinPoint pjp){
Object returnValue = null;
try{
if(登录过){
returnValue = pjp.proceed();
}else{
// 由shiro控制跳转到指定的页面,由pring-shiro.xml提供跳转的
}
}
}
// 注意:没有shiro项目的功能照样跑起来,添加shiro实际就是横切,把shiro横切
// 实际是代理模式
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-allartifactId>
<version>1.2.3version>
dependency>
/**
* 用ini文件模拟数据库,测试Shiro的认证
*/
public class ShiroTest {
@Test
public void testLogin() throws Exception{
// 1. 创建securityManager工厂对象:加载配置文件,创建工厂对象
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
// 2. 通过工厂对象,创建SecurityManager对象
SecurityManager securityManager = factory.getInstance();
// 3. 将securityManager绑定到当前运行环境中,让系统随时随地都可以访问该对象
SecurityUtils.setSecurityManager(securityManager);
// 4. 创建当前登录的主体,注意,此时主体没有经过认证
Subject subject = SecurityUtils.getSubject();
// 5. 收集主体登录的身份/凭证,即账号密码
UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "666");
// 6. 主体登录
subject.login(token);
// 7. 判断登录是否成功, 成功返回true,失败返回false
System.out.println("验证登录是否成功:" + subject.isAuthenticated());
// 8. 注销
subject.logout();
System.out.println("验证是否登录成功(退出之后返回false):" + subject.isAuthenticated());
}
}
运行结果:
验证登录是否成功:true
验证是否登录成功(退出之后返回false):false
public class MyRealm extends AuthorizingRealm {
// 授权操作
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
// 认证操作
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println(authenticationToken);
String username = (String)authenticationToken.getPrincipal();
if(!"zhangsan".equals(username)){
return null;
}
String password="666";
// info对象表示realm登录对比信息,参数1:用户信息,参数2:表示密码,参数:3:当前ralms的名字
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password, getName());
return info;
}
// 指定当前自定义Realm的名字
public String getName() {
return "MyRealm";
}
}
自定义ini配置文件
# 自定义realm
myRealm=com.wyq.shiro.realm.MyRealm
# 指定securityManager的realms实现
securityManager.realms=$myRealm
@Test
public void testMD5() throws Exception{
String password = "666";
// 加密
Md5Hash md5Hash = new Md5Hash(password);
System.out.println(md5Hash);
// 加密:md5 + salt
md5Hash = new Md5Hash(password, "salt");
System.out.println(md5Hash);
// 加密:md5 + salt + 散列次数
md5Hash = new Md5Hash(password, "salt", 3);
System.out.println(md5Hash);
}
Shiro之加密算法认证
public class PasswordRealm extends AuthorizingRealm {
// 授权
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
// 认证
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
// 参数authenticationToken:表示登录时包装的UsernamePasswordToken
// 通过用户名到数据库中查用户信息,封装成一个AuthonticationInfo对象返回,方便认证器进行对比
// 获取token中的用户名
String username = (String)authenticationToken.getPrincipal();
if(!"zhangsan".equals(username)){
return null;
}
// 模拟数据库中保存之后密文
String password="c2fde5f6da6c08a5f4da78d5fd803bcd";
// info对象表示realm登录对比信息,参数1:用户信息,参数2:表示密码,参数3:表示加密的salt, 参数:4:当前ralms的名字
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password , ByteSource.Util.bytes("salt"), getName());
return info;
}
@Override
public String getName() {
return "PasswordRealm";
}
}
[main]
# 定义凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
# 散列算法
credentialsMatcher.hashAlgorithmName=md5
# 散列次数
credentialsMatcher.hashIterations=3
# 自定义realm
myRealm=com.wyq.shiro.realm.PasswordRealm
myRealm.credentialsMatcher=$credentialsMatcher
# 指定securityManager的realms实现
securityManager.realms=$myRealm
Subject subject = SecurityUtils.getSubject();
if(subject.hasRole("admin")){
// 有权限
}else{
// 无权限
}
@RequiresRoles("admin")
public void help(){
}
// 先引入标签库
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<shiro:hasRole name="admin">
<!-- 有权限 -->
</shiro:hasRole>
@Test
public void testHasRole()throws Exception{
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-permission.ini");
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "666");
subject.login(token);
// 进行授权操作前提:用户必须通过认证
System.out.println("是否拥有role1权限:" + subject.hasRole("role1"));
System.out.println(subject.hasAllRoles(Arrays.asList("role1", "role2", "role3")));
System.out.println(Arrays.toString(subject.hasRoles(Arrays.asList("role1", "role2", "role3"))));
// 如果拥有角色不做任何操作,没有则抛出org.apache.shiro.authz.UnauthorizedException异常
subject.checkRole("role1");
// 判断是否拥有创建权限
System.out.println(subject.isPermitted("user:create"));
}
[users]
# 模拟数据库用户列表,账号=密码
zhangsan=666,role1,role2
lisi=888,role2
[roles]
# 角色role1对资源user拥有create,update的权限
role1=user:create,user:update
# 角色role2对资源user拥有create,delete的权限
role2=user:create,user:delete
# 角色role3对资源user拥有create的权限
role3=user:create
# 自定义realm
myRealm=com.wyq.shiro.realm.PermissionRealm
# 指定securityManager的realms实现
securityManager.realms=$myRealm
public class PermissionRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
// principalCollection 用户的凭证信息
String username = (String)principalCollection.getPrimaryPrincipal();
// 模拟查询数据库: 查询用户实现指定的角色,以及用户授权
List<String> roles = new ArrayList<>();
List<String> permission = new ArrayList<>();
roles.add("role1");
permission.add("user:*");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRoles(roles);
info.addStringPermissions(permission);
return info;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
String username = (String)authenticationToken.getPrincipal();
if(!"zhangsan".equals(username)){
return null;
}
String password="666";
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username, password, getName());
return simpleAuthenticationInfo;
}
public String getName() {
return "PermissionRealm";
}
}
@Test
public void testHasRoleByRealm()throws Exception{
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-permission-realm.ini");
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "666");
subject.login(token);
// 判断是否拥有某个权限
System.out.println(subject.isPermitted("user:xx"));
}
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-coreartifactId>
<version>1.2.3version>
dependency>
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-webartifactId>
<version>1.2.3version>
dependency>
<context-param>
<param-name>shiroEnvironmentClassparam-name>
<param-value>org.apache.shiro.web.env.IniWebEnvironmentparam-value>
context-param>
<context-param>
<param-name>shiroConfigLocationsparam-name>
<param-value>classpath:shiro.iniparam-value>
context-param>
<listener>
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListenerlistener-class>
listener>
<filter>
<filter-name>shiroFilterfilter-name>
<filter-class>org.apache.shiro.web.servlet.ShiroFilterfilter-class>
filter>
<filter-mapping>
<filter-name>shiroFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
[main]
#默认是/login.jsp
authc.loginUrl=/login
#用户无需要的角色时跳转的页面
roles.unauthorizedUrl=/nopermission.jsp
#用户无需要的权限时跳转的页面
perms.unauthorizedUrl=/nopermission.jsp
#登出之后重定向的页面
logout.redirectUrl=/login
[users]
admin=666,admin
zhangsan=666,deptMgr
[roles]
admin=employee:*,department:*
deptMgr=department:view
[urls]
#静态资源可以匿名访问
/static/**=anon
#访问员工列表需要身份认证及需要拥有admin角色
/employee=authc,roles[admin]
#访问部门列表需要身份认证及需要拥有department:view的权限
/department=authc,perms["department:view"]
#当请求loginOut,会被logout捕获并清除session
/loginOut=logout
#所有的请求都需要身份认证
/**=authc
处理登录认证@WebServlet(name = "loginServlet", urlPatterns = "/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String exceptionClassName = (String)req.getAttribute("shiroLoginFailure");
// 不处理登录成功的情况,shiro认证会自动跳转到上一个请求路径
// 处理登录失败的情况
if(exceptionClassName != null) {
if(UnknownAccountException.class.getName().equals(exceptionClassName)) {
req.setAttribute("errorMsg", "账号不存在");
}else if(IncorrectCredentialsException.class.getName().equals(exceptionClassName)) {
req.setAttribute("errorMsg", "用户名或密码错误");
}else {
req.setAttribute("errorMsg", "未知的登录异常");
}
}
// 登录失败还是跳回login页面
req.getRequestDispatcher("/WEB-INF/views/login.jsp").forward(req, resp);
}
}
<dependency>
<groupId>commons-logginggroupId>
<artifactId>commons-loggingartifactId>
<version>1.1.3version>
dependency>
<dependency>
<groupId>commons-collectionsgroupId>
<artifactId>commons-collectionsartifactId>
<version>3.2.1version>
dependency>
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-coreartifactId>
<version>1.2.2version>
dependency>
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-webartifactId>
<version>1.2.2version>
dependency>
<dependency>
<groupId>net.sf.ehcachegroupId>
<artifactId>ehcache-coreartifactId>
<version>2.6.8version>
dependency>
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-ehcacheartifactId>
<version>1.2.2version>
dependency>
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-quartzartifactId>
<version>1.2.2version>
dependency>
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-springartifactId>
<version>1.2.2version>
dependency>
web.xml配置
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>Archetype Created Web Applicationdisplay-name>
<servlet>
<servlet-name>SpringMVCservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:mvc.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>SpringMVCservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
<filter>
<filter-name>CharacterEncodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>UTF-8param-value>
init-param>
<init-param>
<param-name>forceEncodingparam-name>
<param-value>trueparam-value>
init-param>
filter>
<filter-mapping>
<filter-name>CharacterEncodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<filter>
<filter-name>shiroFilterfilter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxyfilter-class>
<init-param>
<param-name>targetFilterLifecycleparam-name>
<param-value>trueparam-value>
init-param>
filter>
<filter-mapping>
<filter-name>shiroFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
web-app>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="md5" />
<property name="hashIterations" value="3" />
bean>
<bean id="userRealm" class="cn.wolfcode.shiro.realm.UserRealm">
<property name="credentialsMatcher" ref="credentialsMatcher"/>
<property name="userDAO" ref="userDAOImpl"/>
<property name="roleDAO" ref="roleDAOImpl"/>
<property name="permissionDAO" ref="permissionDAOImpl"/>
bean>
<property name="configLocation" value="classpath:shiro-ehcache.xml" />
<property name="shared" value="true">property>
bean>
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManager" ref="ehCacheManager"/>
bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="userRealm"/>
<property name="cacheManager" ref="cacheManager"/>
bean>
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/login"/>
<property name="unauthorizedUrl" value="/nopermission.jsp"/>
<property name="filterChainDefinitions">
<value>
/logout=logout
/**=authc
value>
property>
bean>
<aop:config proxy-target-class="true">aop:config>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager" />
bean>
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="org.apache.shiro.authz.UnauthorizedException">redirect:/nopermission.jspprop>
props>
property>
bean>
public class UserRealm extends AuthorizingRealm {
@Setter
private IUserDAO userDAO;
@Setter
private IRoleDAO roleDAO;
@Setter
private IPermissionDAO permissionDAO;
//认证操作
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//从token中获取登录的用户名, 查询数据库返回用户信息
String username = (String) token.getPrincipal();
User user = userDAO.getUserByUsername(username);
SimpleAuthenticationInfo info = null;
if(username != null){
info = new SimpleAuthenticationInfo(user, user.getPassword(), ByteSource.Util.bytes(user.getUsername()), getName());
}
return info;
}
//授权操作
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
User user = (User) principals.getPrimaryPrincipal();
// 根据用户id查询所有角色
List<String> roles = roleDAO.getRoleSnByUserId(user.getId());
// 根据用户id查询该用户拥有的权限
List<String> permissions = permissionDAO.getPermissionResourceByUserId(user.getId());
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermissions(permissions);
info.addRoles(roles);
return info;
}
@Override
public String getName() {
return "UserRealm";
}
//清除缓存
public void clearCached() {
//获取当前等的用户凭证,然后清除
PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();
super.clearCache(principals);
}
}
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<shiro:principal property="username">shiro:principal>
<shiro:hasRole name="管理员">
用户拥有角色
shiro:hasRole>
<shiro:hasPermission name="department:list">
用户拥有该权限
shiro:hasPermission>