spring boot vue 前后端分离 shiro 认证失败
程序员文章站
2022-06-13 15:31:59
...
shiro 认证失败 ,但是用户有权限
后端代码
usersController
package com.graduate.twentyone.controller;
import com.graduate.twentyone.diman.RestDate;
import com.graduate.twentyone.diman.Users;
import org.apache.catalina.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@Controller
@ResponseBody
@CrossOrigin
public class UsersController {
/***
*@methodName userslogin
*@方法功能描述
*@params
* @param users
*@return com.graduate.twentyone.diman.RestDate
*@exception
*@author $風~$
*@Date 2021/3/22
*/
@RequestMapping(value = "userlogin" ,method = RequestMethod.POST)
// @GetMapping("/userlogin")
public RestDate userslogin(@RequestBody Users users) {
String uname = users.getUname();
String pwd = users.getPwd();
System.out.println( " 222 uname " + uname);
System.out.println(" 333 pwd " + pwd);
Subject subject = SecurityUtils.getSubject();
RestDate<Object> restDate = new RestDate<>(800, "error", "返回的数据");
String authToken1 = (String) subject.getSession().getId();
System.out.println(authToken1+" authtoken");
Map map = new HashMap();
map.put("authToken",authToken1);
try {
subject.login(new UsernamePasswordToken(uname, pwd));
} catch (IncorrectCredentialsException incorrectCredentialsException) {
restDate = new RestDate<>(2, "密码错误", "返回的数据");
return restDate;
} catch (UnknownAccountException UnknownAccountException) {
restDate = new RestDate<>(1, "账号错误", "返回的数据");
return restDate;
} catch (NullPointerException nullPointerException) {
restDate = new RestDate<>(0, "未输入信息", "返回的数据");
return restDate;
}
if (subject.isAuthenticated()) {
restDate = new RestDate<>(-1, "success",map);
return restDate;
}
return restDate;
}
}
foodController
package com.graduate.twentyone.controller;
import com.graduate.twentyone.diman.Food;
import com.graduate.twentyone.diman.RestDate;
import com.graduate.twentyone.service.FoodService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.security.auth.Subject;
import java.sql.SQLOutput;
import java.util.List;
import java.util.Map;
@RestController
@CrossOrigin
public class FoodController {
@Autowired
FoodService foodService;
// @RequiresUser
// @RequiresAuthentication
// @RequiresRoles("admin")
@RequiresPermissions("food:add")
@RequestMapping(value = "/addfood",method = RequestMethod.POST)
public RestDate addfood(@RequestBody Food food){
Integer addfood = foodService.addfood(food);
RestDate restDate = new RestDate(500,"发生未知错误","返回的数据");
if (addfood == 1){
restDate = new RestDate(-1,"成功","返回的数据");
}
return restDate;
}
@RequiresPermissions("food:update")
@RequestMapping(value = "/updatefood",method = RequestMethod.POST)
public RestDate updatefood(@RequestBody Food food){
Integer updatefood = foodService.updatefood(food);
RestDate restDate = new RestDate(500,"发生未知错误","返回的数据");
if (updatefood == 1){
restDate = new RestDate(-1,"成功","返回的数据");
}
return restDate;
}
@RequiresPermissions("food:delete")
@RequestMapping(value = "/deletefood",method = RequestMethod.POST)
public RestDate deletefood(@RequestBody Food food){
food.setStatus(0);
Integer updatefood = foodService.updatefood(food);
RestDate restDate = new RestDate(500,"发生未知错误","返回的数据");
if (updatefood == 1){
restDate = new RestDate(-1,"成功","返回的数据");
}
return restDate;
}
@RequestMapping(value = "/selectfood",method = RequestMethod.POST)
@RequiresPermissions("food:select")
// @GetMapping("/selectfood")
public RestDate selectfood(){
System.out.println("selectfood");
System.out.println(SecurityUtils.getSubject().isAuthenticated());
boolean permitted = SecurityUtils.getSubject().isPermitted("food:select");
System.out.println("此处权限food:select为:"+permitted);
List<Food> selectfood = foodService.selectfood();
RestDate restDate = new RestDate(500,"发生未知错误",selectfood);
if (selectfood.size()>=0){
restDate = new RestDate(-1,"food 查询成功","返回的数据");
}
return restDate;
}
}
MyRealm
package com.graduate.twentyone.util.shiro;
import com.graduate.twentyone.diman.Promission;
import com.graduate.twentyone.diman.Users;
import com.graduate.twentyone.mapper.UsersMapper;
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.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.List;
public class MyRealm extends AuthorizingRealm {
@Autowired
UsersMapper usersMapper;
//获取当前用户的身份
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
String uname = authenticationToken.getPrincipal().toString();
// 通过用户名查找该用户的信息
Users user = usersMapper.login(uname);
System.out.println("asdsdsdsdsdsd:"+user);
//返回认证信息对象
if (user != null) {
AuthenticationInfo info = new SimpleAuthenticationInfo(user.getUname(), user.getPwd(), "myRealm");
return info;
}
return null;
}
// 获取当前用户的所有权限
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
// 获取权限信息
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
// 获取用户名
String uname = (String) principalCollection.getPrimaryPrincipal();
// 获取用户的身份
String loginrname = usersMapper.loginrname(uname);
// 添加进去
info.addRole(loginrname);
// 获取用户的权限
List<Promission> loginpro = usersMapper.loginpro(uname);
// 遍历添加
for (int i = 0; i < loginpro.size(); i++) {
System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
System.out.println(loginpro.get(i).getPname());
info.addStringPermission(loginpro.get(i).getPname());
}
return info;
}
}
ShiroConfig
package com.graduate.twentyone.util.shiro;
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.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ShiroConfig {
@Bean("realm")
public MyRealm getRealm() {
return new MyRealm();
}
@Bean("securityManager")
public DefaultWebSecurityManager getSecurityManager(MyRealm realm,DefaultWebSessionManager sessionManager) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm);
securityManager.setSessionManager(sessionManager);
return securityManager;
}
@Bean
public DefaultWebSessionManager getDefaultWebSessionManager(){
// 这个是另一个文件的
return new ShiroSession();
}
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//注入核心安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
return shiroFilterFactoryBean;
}
//开启对shior注解的支持
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
proxyCreator.setProxyTargetClass(true);
return proxyCreator;
}
@Bean
public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor(){
return new LifecycleBeanPostProcessor();
}
}
ShiroSession
package com.graduate.twentyone.util.shiro;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.util.StringUtils;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.Serializable;
public class ShiroSession extends DefaultWebSessionManager {
/**
* 定义的请求头中使用的标记key,用来传递 token
*/
private static final String AUTH_TOKEN = "authToken";
private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";
public ShiroSession() {
super();
//设置 shiro session 失效时间,默认为30分钟,这里现在设置为15分钟
setGlobalSessionTimeout(MILLIS_PER_MINUTE * 15);
}
/**
* 获取sessionId,原本是根据sessionKey来获取一个sessionId
* 重写的部分多了一个把获取到的token设置到request的部分。这是因为app调用登陆接口的时候,是没有token的,登陆成功后,产生了token,我们把它放到request中,返回结
* 果给客户端的时候,把它从request中取出来,并且传递给客户端,客户端每次带着这个token过来,就相当于是浏览器的cookie的作用,也就能维护会话了
* @param request ServletRequest
* @param response ServletResponse
* @return Serializable
*/
@Override
protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
//获取请求头中的 AUTH_TOKEN 的值,如果请求头中有 AUTH_TOKEN 则其值为sessionId。shiro就是通过sessionId 来控制的
System.out.println("ShiroSession");
String sessionId = WebUtils.toHttp(request).getHeader("AUTH_TOKEN");
System.out.println(sessionId);
if (StringUtils.isEmpty(sessionId)){
//如果没有携带id参数则按照父类的方式在cookie进行获取sessionId
return super.getSessionId(request, response);
} else {
//请求头中如果有 authToken, 则其值为sessionId
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);
//sessionId
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sessionId);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
return sessionId;
}
}
}
————————————————————————————————————————————————————————————————————
前端代码
log.js
import request from '../utils/request';
export const login = (data) => {
return request({
url: '/userlogin',
method: 'post',
data:data ,
});
};
登录vue
methods: {
submitForm() {
var that = this;
this.$refs.login.validate(valid => {
if (valid) {
var uname = that.param.username;
var pwd = that.param.password;
var ddd = JSON.stringify({
// 参数
uname,
pwd
});
this.userlogin(ddd);
} else {
that.$message.error('请输入账号和密码');
console.log('error submit!!');
return false;
}
});
},
userlogin(ddd) {
var that = this;
console.log('userlogin');
login(ddd)
.then(res => {
console.log(res);
if (res.code == -1) {
that.$message.success('登录成功');
//设置authToken 在本地存储 ( 这一行的上下块是一个整体)
localStorage.setItem("authToken",res.data.authToken)
localStorage.setItem('ms_username', this.param.username);
that.$router.push('/');
} else if (res.code == 1) {
that.$message.error('账号错误');
console.log('error submit!!');
return false;
} else if (res.code == 2) {
this.$message.error('密码错误');
console.log('error submit!!');
return false;
}
})
.catch(res => {});
}
}
request.js
import axios from 'axios';
// axios.defaults.withCredentials = true;
const service = axios.create({
// process.env.NODE_ENV === 'development' 来判断是否开发环境
// easy-mock服务挂了,暂时不使用了
// baseURL: 'https://www.easy-mock.com/mock/592501a391470c0ac1fab128',
baseURL: 'http://localhost:8080',
headers: {'Content-Type': 'application/json'},
// withCredentials: true,
timeout: 5000
});
service.interceptors.request.use(
config => {
console.log(config.url)
console.log(localStorage.getItem('authToken'))
// 给每个请求都加上token请求头 || config.url === '/checkLogin' && (localStorage.getItem('token') != null)
if (config.url !== '/userlogin') {
if (localStorage.getItem('authToken')) {
// config.headers.token = localStorage.getItem('token');
在请求头设置AUTH_TOKEN的值
后端会获取这个值
config.headers.AUTH_TOKEN =localStorage.getItem('authToken');
console.log(config.headers.AUTH_TOKEN)
} else {
this.$router.push('/');
}
}
return config;
},
error => {
console.log(error);
return Promise.reject();
}
);
service.interceptors.response.use(
response => {
if (response.status === 200) {
return response.data;
} else {
Promise.reject();
}
},
error => {
console.log(error);
return Promise.reject();
}
);
export default service;
推荐阅读
-
Spring Boot + Vue 前后端分离开发之前端网络请求封装与配置
-
学会Spring Boot+Vue前后端分离开发(1)之前后端搭建
-
Spring Boot + Vue前后端分离项目,Maven自动打包整合
-
vue-cli+spring boot前后端分离跨域及session丢失解决办法
-
Spring Boot + Vue前后端分离(三)实现登录功能
-
搭建spring-boot+vue前后端分离框架并实现登录功能
-
spring boot + vue +nginx实现前后端分离
-
Spring boot 和Vue前后端分离
-
spring-boot gradle vue 前后端分离项目在腾讯云上部署到 tomcat nginx
-
spring boot vue 前后端分离 shiro 认证失败