package com.cdz.demo0216yiguo.config;
import com.cdz.demo0216yiguo.realm.UserRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
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.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* shiro的配置类
* @Configuration 用于定义配置类,该类的各个方法返回各种对象实现系统的配置
*/
@Configuration
public class ShiroConfig {
/**
* 缓存配置
*/
@Bean(name = "ehCacheManager")
@DependsOn("lifecycleBeanPostProcessor")
public EhCacheManager ehCacheManager(){
EhCacheManager ehCacheManager = new EhCacheManager();
return ehCacheManager;
}
/**
* 返回自定义会话管理器
* @return
*/
@Bean
public SessionManager sessionManager(){
return new ShiroSessionManager();
}
//加入spring的容器,自动配置
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher(){
//密码匹配器
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("md5");//设置加密算法,加密次数
matcher.setHashIterations(2); //设置加密的次数
matcher.setStoredCredentialsHexEncoded(true);//设置密文16进制,false是base64编码
return matcher;
}
//返回自定义Realm
@Bean
public UserRealm userRealm(){
UserRealm userRealm = new UserRealm();
userRealm.setCredentialsMatcher(hashedCredentialsMatcher());//设置密码配置器
userRealm.setCachingEnabled(false);//取消缓存
return userRealm;
}
//返回安全管理器
@Bean
public SecurityManager securityManager(){
// //创建web项目的安全管理器
// DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// securityManager.setRealm(userRealm());
// return securityManager;
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm()); //Realm配置
securityManager.setCacheManager(ehCacheManager());
//配置自定义会话管理器
securityManager.setSessionManager(sessionManager());
return securityManager;
}
//返回过滤器对象
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
factoryBean.setSecurityManager(securityManager);//配置安全管理器
factoryBean.setLoginUrl("login.html");//配置登录URL,登录失败进行自动跳转
//配置授权失败Url
factoryBean.setUnauthorizedUrl("404.html");
//配置拦截规则,不拦截在前面,拦截在后面
//anon不拦截,authc拦截
Map map=new LinkedHashMap<>();
map.put("/login.html","anon");
map.put("/register.html" ,"anon");
map.put("/index.html" ,"anon");
map.put("/goods.html" ,"anon");
map.put("/goodsDetails.html" ,"anon");
map.put("/404.html","anon");
map.put("/static/**","anon");
map.put("/user/login/**","anon");
map.put("/register/login","anon");
map.put("/type/**" ,"anon");
map.put("/product/**" ,"anon");
map.put("/**","authc");//表示所有拦截资源
factoryBean.setFilterChainDefinitionMap(map);
return factoryBean;
}
//下面的配置用于启动@RequiresRoles 和@ReqriresPermissions 注解
//基于springaop的实现
//配置后置处理器
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
return new LifecycleBeanPostProcessor();
}
@Bean
@DependsOn({"lifecycleBeanPostProcessor"})
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
creator.setProxyTargetClass(true);
return creator;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(){
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager());
return advisor;
}
}
注:在ShiroConfig中,添加返回会话管理器对象的方法,在返回安全管理器的方法中,给安全管理器配置会话管理对象
package com.cdz.demo0216yiguo.config;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Configuration
public class ShiroCrosConfig extends BasicHttpAuthenticationFilter {
@Override
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin")); //标识允许哪个域到请求,直接修改成请求头的域
httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");//标识允许的请求方法
// 响应首部 Access-Control-Allow-Headers 用于 preflight request (预检请求)中,列出了将会在正式请求的 Access-Control-Expose-Headers 字段中出现的首部信息。修改为请求首部
httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
//给option请求直接返回正常状态
if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
httpServletResponse.setStatus(HttpStatus.OK.value());
return false;
}
return super.preHandle(request, response);
}
}
package com.cdz.demo0216yiguo.config;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.util.WebUtils;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.util.StringUtils;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.Serializable;
public class ShiroSessionManager extends DefaultWebSessionManager {
//这个是请求头中保存sessionid的名称
private static final String AUTHORIZATION = "authToken";
private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";
public ShiroSessionManager() {
super();
}
/**
* 重写返回sessionid的方法
* @param request
* @param response
* @return
*/
@Override
protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
//读取请求头中的sessionid
String id = WebUtils.toHttp(request).getHeader(AUTHORIZATION);
System.out.println("id:" + id);
if (StringUtils.isEmpty(id)) {
//如果没有携带id参数则按照父类的方式在cookie进行获取
System.out.println("super:" + super.getSessionId(request, response));
return super.getSessionId(request, response);
} else {
//如果请求头中有 authToken 返回sessionId
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;
}
}
}
注:ShiroSessionManager类继承DefaultWebSessionManager 会话管理器,重写getSessionId方法,获得请求头中的sessionid交给shiro验证
后台controller获得已登录id
package com.cdz.demo0216yiguo.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cdz.demo0216yiguo.bean.JsonResult;
import com.cdz.demo0216yiguo.bean.LoginId;
import com.cdz.demo0216yiguo.bean.User;
import com.cdz.demo0216yiguo.service.IUserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.Serializable;
import java.util.List;
@RestController
@RequestMapping("user")
//@CrossOrigin
public class UserControlelr {
@Autowired
private IUserService service;
@ResponseBody
@GetMapping("user-list")
public JsonResult listUsers(){
try{
List users=service.list();
return new JsonResult(200,"success",users);
}catch (Exception e){
e.printStackTrace();
return new JsonResult(500,"failed",e.getMessage());
}
}
@GetMapping("/login/username/{username}/pwd/{password}")
public JsonResult loginY(@PathVariable("username") String userName,@PathVariable("password") String userPwd,String remember, HttpSession session){
System.out.println("来了没");
UsernamePasswordToken token = new UsernamePasswordToken();
token.setUsername(userName);
token.setPassword(userPwd.toCharArray());
Subject subject= SecurityUtils.getSubject();
boolean isNo=true;
System.out.println(subject.isAuthenticated());
if(subject.isAuthenticated()==true){
isNo=false;
}else{
isNo=false;
}
//判断是否有记住我
// System.out.println("记住我:"+remember);
// remember="true";
// if ("true".equals(remember)) {
// token.setRememberMe(true);
// }else{
// token.setRememberMe(false);
// }
if(!isNo){
try {
subject.login(token);
session.setAttribute("username",userName);
User user_name = service.getOne(new QueryWrapper().eq("user_name", userName));
System.out.println("用户:"+user_name);
Serializable id = subject.getSession().getId();
LoginId ids=new LoginId();
ids.setUserId(user_name.getUserId());
ids.setTokenId(id);
System.out.println("id="+ids);
return new JsonResult(200,"success",ids);
}catch (AuthenticationException e){
e.printStackTrace();
}
}
return new JsonResult(200,"failed","");
}
@RequestMapping("add")
public JsonResult userAdd(User user,@RequestParam(value="pic" ,required = false) MultipartFile file){
try{
User user1=null;
if(user!=null){
List users = service.list();
for(User u:users){
if(u.getUserTel().equals(user.getUserTel())){
return new JsonResult(200,"failed","");
}
}
if(file!=null){
//获得原来的名
String filename = file.getOriginalFilename();
//截取后缀名
String suffix = filename.substring(filename.lastIndexOf("."));
//当前时间创建新名
filename=System.currentTimeMillis()+suffix;
File upoladFile = new File("G:\\tomcat\\apache-tomcat-8.0.53\\webapps\\upload_images\\" + filename);
//保存文件到对象属性中
user.setUserImg(filename);
//上传文件
//上传文件
try{
file.transferTo(upoladFile);
}catch (IOException e){
e.printStackTrace();
}
}
String name=user.getUserName();
SimpleHash simpleHash6 = new SimpleHash("md5", user.getUserPwd(), ByteSource.Util.bytes(name),2);
System.out.println("加密6后:"+simpleHash6.toString());
user.setUserPwd(simpleHash6.toString());
//System.out.println(user);
user.setRoleId(57414897);
service.save(user);
}
System.out.println("没有成功");
return new JsonResult(200,"success",user1);
}catch (Exception e){
e.printStackTrace();
return new JsonResult(500,"failed",e.getMessage());
}
}
}
loadHtml:function(){
//获得登录后保存的sessionid
this.token = localStorage.getItem("tokenId");
//添加到请求头中,请求头名称和Shiro的会话管理器配置的一样
axios.defaults.headers.common["authToken"] = this.token;
},
注:客户端登录成功后用localStorage保存sessionid,登录完,再请求后台时,把sessionid取出来,配置到请求头里