1.自定义ShiroConfiguration
package com.hgys.iptv.configuration.shiro;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
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 org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
/**
* @author: wangzhen
* @date:2019/4/19 16:53
*/
@Configuration
public class ShiroConfiguration {
//将自己的验证方式加入容器
@Bean
public ShiroRealmDetails getShiroRealmDetails() {
return new ShiroRealmDetails();
}
//权限管理,配置主要是Realm的管理认证
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(getShiroRealmDetails());
securityManager.setSessionManager(getShiroSessionManager());
return securityManager;
}
//自定义session管理
@Bean
public ShiroSessionManager getShiroSessionManager(){
return new ShiroSessionManager();
}
//Filter工厂,设置对应的过滤条件和跳转条件
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
// System.out.println("ShiroConfiguration.shiroFilterFactoryBean()");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
//注意过滤器配置顺序 不能颠倒
filterChainDefinitionMap.put("/logout", "logout");
// 配置不会被拦截的action 顺序判断
// filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap.put("/login", "anon");
filterChainDefinitionMap.put("/LoginFail", "anon");
filterChainDefinitionMap.put("/unauth", "anon");
// 现在资源的角色
// filterChainDefinitionMap.put("/admin.html", "roles[admin]");
// filterChainDefinitionMap.put("/user.html", "roles[user]");
filterChainDefinitionMap.put("/**", "authc");
//filterChainDefinitionMap.put("/**", "user");--设置rememberMe(true),在/**=authc权限下是不起作用的,需要user
//配置shiro默认登录action,前后端分离中登录界面跳转应由前端路由控制,后台仅返回json数据
shiroFilterFactoryBean.setLoginUrl("/loginHtml");
// 登录成功后要跳转的链接
shiroFilterFactoryBean.setSuccessUrl("/LoginSuccess");
//未授权界面;
shiroFilterFactoryBean.setUnauthorizedUrl("/unauth");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
//处理未授权异常跳转问题
@Bean
public SimpleMappingExceptionResolver simpleMappingExceptionResolver(){
SimpleMappingExceptionResolver resolver=new SimpleMappingExceptionResolver();
Properties properties = new Properties();
properties.setProperty("UnauthorizedException","/unauth");
resolver.setExceptionMappings(properties);
return resolver;
}
}
2.继承AuthorizingRealm重写两个方法
package com.hgys.iptv.configuration.shiro;
import com.hgys.iptv.model.Permission;
import com.hgys.iptv.model.Role;
import com.hgys.iptv.model.User;
import com.hgys.iptv.service.LoginService;
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.springframework.beans.factory.annotation.Autowired;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* @author: wangzhen
* @date:2019/4/19 16:39
*/
public class ShiroRealmDetails extends AuthorizingRealm {
@Autowired
private LoginService loginService;
/**
* 鉴权授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("进入doGetAuthorizationInfo授权。");
//获取登录用户名
String principal= (String) principalCollection.getPrimaryPrincipal();
// 根据用户名来查询数据库赋予用户角色,权限(查数据库)
User user = loginService.findByUsername(principal);
SimpleAuthorizationInfo simpleAuthorizationInfo = null;
if(user!=null){
Set<String> roles = new HashSet<>();
Set<String> permissions = new HashSet<>();
simpleAuthorizationInfo = new SimpleAuthorizationInfo();
for (Role role:user.getRoles()) {
roles.add(role.getName());
for (Permission permission:role.getPermissions()) {
permissions.add(permission.getPermission());
}
}
//关联角色
simpleAuthorizationInfo.setRoles(roles);
//关联权限
simpleAuthorizationInfo.setStringPermissions(permissions);
}
System.out.println(principal+"具有的角色:=="+Arrays.toString(simpleAuthorizationInfo.getRoles().toArray()));
System.out.println(principal+"具有的权限:=="+Arrays.toString(simpleAuthorizationInfo.getStringPermissions().toArray()));
return simpleAuthorizationInfo;
}
/**
* 获取身份验证信息
* @param authenticationToken 用户身份信息 token
* @return 返回封装了用户信息的 AuthenticationInfo 实例
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("进入doGetAuthenticationInfo查用户信息。");
if (authenticationToken.getPrincipal() == null) {
return null;
}
// UsernamePasswordToken upToken = (UsernamePasswordToken) authenticationToken;
// // 获得从表单传过来的用户名
// String username = upToken.getUsername();
//获取用户信息
String name = authenticationToken.getPrincipal().toString();
// 从数据库查看是否存在用户
User user = loginService.findByUsername(name);
if (user == null) {
throw new UnknownAccountException("用户名不存在!");
}
//验证authenticationToken和simpleAuthenticationInfo的信息
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
name,
user.getPassword(),
getName());
return simpleAuthenticationInfo;
}
}
3.自定义ShiroSessionManager(可选)
package com.hgys.iptv.configuration.shiro;
import org.springframework.util.StringUtils;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.util.WebUtils;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.Serializable;
/**
* @author: wangzhen
* @date:2019/4/20 21:13
*/
public class ShiroSessionManager extends DefaultWebSessionManager {
private static final String AUTHORIZATION = "Authorization";
private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";
@Override
protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
String id = WebUtils.toHttp(request).getHeader(AUTHORIZATION);
//如果请求头中有 Authorization 则其值为sessionId
if (!StringUtils.isEmpty(id)) {
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
return id;
} else {
//否则按默认规则从cookie取sessionId
return super.getSessionId(request, response);
}
}
}
4.自定义ShiroCatheManager(可选)
5.subject.login(new UsernamePasswordToken(username, password))
@RequestMapping("/login")
public String login(@RequestParam("username") String username, @RequestParam("password") String password) {
Subject subject = SecurityUtils.getSubject();
// 验证用户是否已登录过
if (!subject.isAuthenticated()) {
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
// token.setRememberMe(true);
try {
subject.login(token);
boolean f =subject.hasRole("ROLE_ADMIN");
System.out.println("admin角色标志=="+f);
return "redirect:/LoginSuccess";
} catch (IncorrectCredentialsException e) {
System.out.println("登录密码错误!!!" + e);
return "redirect:/LoginFail";
} catch (ExcessiveAttemptsException e) {
System.out.println("登录失败次数过多!!!" + e);
} catch (LockedAccountException e) {
System.out.println("帐号已被锁定!!!" + e);
} catch (DisabledAccountException e) {
System.out.println("帐号已被禁用!!!" + e);
} catch (ExpiredCredentialsException e) {
System.out.println("帐号已过期!!!" + e);
} catch (UnknownAccountException e) {
System.out.println("帐号不存在!!!" + e);
} catch (UnauthorizedException e) {
System.out.println("您没有得到相应的授权!" + e);
return "redirect:/unauth";
} catch (Exception e) {
System.out.println("出错!!!" + e);
}
return "/login";
}
// 已成功登录过则直接重定向到LoginSuccess
return "redirect:/LoginSuccess";
}
6.在方法上设置需要权限
@RequestMapping("/showUserHtml")
@RequiresRoles(value = { "ROLE_USER", "ROLE_ADMIN"},logical = Logical.OR)
// @RequiresPermissions("user:query")
@RequiresPermissions("QUERY")
public String userHtml() {
return "/user";
}