springboot+shiro+jwt+vue配置全攻略
一、後端配置 0.pom.xml
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.11.0</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
1.shiro配置檔案 ShiroConfiguration.java
@Slf4j
@Configuration
public class ShiroConfiguration {
/**
* shiro 安全過濾鏈
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// shiroFilterFactoryBean.setUnauthorizedUrl("/login");
// 新增自己的過濾器並且取名為jwt
Map<String, Filter> filterMap = new HashMap<>();
filterMap.put("jwt", new JWTFilter());
shiroFilterFactoryBean.setFilters(filterMap);
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setUnauthorizedUrl("/401");
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
// 所有的請求通過我們自己的JWT filter
filterChainDefinitionMap.put("/**", "jwt");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
/**
* web 安全管理器
* @return
*/
@Bean(name = "securityManager")
public DefaultSecurityManager getDefaultSecurityManager(@Qualifier("myRelam") MyRealm myRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm);
return securityManager;
}
@Bean(name="myRelam")
public MyRealm getMyRealm() {
return new MyRealm();
}
/**
* 下面的程式碼是新增註解支援
*/
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
// 強制使用cglib,防止重複代理和可能引起代理出錯的問題
// https://zhuanlan.zhihu.com/p/29161098
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
}
2.jwt過濾器
JWTFilter.jav
import com.fasterxml.jackson.databind.ObjectMapper;
import com.szht.cbhs.core.http.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
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;
import java.io.IOException;
@Slf4j
public class JWTFilter extends BasicHttpAuthenticationFilter {
/**
* 判斷使用者是否想要登入。
* 檢測header裡面是否包含Authorization欄位即可
*/
@Override
protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
HttpServletRequest req = (HttpServletRequest) request;
String authorization = req.getHeader("Authorization");
log.info("判斷使用者是否想要登入:{}",authorization);
return authorization != null;
}
/**
*
*/
@Override
protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String authorization = httpServletRequest.getHeader("Authorization");
log.info("判斷使用者是否想要登入x:{}",authorization);
JWTToken token = new JWTToken(authorization);
// 提交給realm進行登入,如果錯誤他會丟擲異常並被捕獲
try {
getSubject(request, response).login(token);
// 如果沒有丟擲異常則代表登入成功,返回true
}catch (Exception e){
return false;
}
return true;
}
/**
* 這裡我們詳細說明下為什麼最終返回的都是true,即允許訪問
* 例如我們提供一個地址 GET /article
* 登入使用者和遊客看到的內容是不同的
* 如果在這裡返回了false,請求會被直接攔截,使用者看不到任何東西
* 所以我們在這裡返回true,Controller中可以通過 subject.isAuthenticated() 來判斷使用者是否登入
* 如果有些資源只有登入使用者才能訪問,我們只需要在方法上面加上 @RequiresAuthentication 註解即可
* 但是這樣做有一個缺點,就是不能夠對GET,POST等請求進行分別過濾鑑權(因為我們重寫了官方的方法),但實際上對應用影響不大
*/
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
System.out.println("isAccessAllowed方法");
try{
return executeLogin(request,response);
}catch (Exception e){
System.out.println("錯誤"+e);
// throw new ShiroException(e.getMessage());
responseError(response,"shiro fail");
return false;
}
// if (isLoginAttempt(request, response)) {
// try {
// executeLogin(request, response);
// } catch (Exception e) {
// response401(request, response);
// }
// }
// return true;
}
/**
* 對跨域提供支援
*/
@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");
httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
// 跨域時會首先傳送一個option請求,這裡我們給option請求直接返回正常狀態
if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
httpServletResponse.setStatus(HttpStatus.OK.value());
return false;
}
return super.preHandle(request, response);
}
/**
* 將非法請求跳轉到 /401
*/
private void response401(ServletRequest req, ServletResponse resp) {
try {
HttpServletResponse httpServletResponse = (HttpServletResponse) resp;
httpServletResponse.sendRedirect("/401");
} catch (IOException e) {
log.error(e.getMessage());
}
}
private void responseError(ServletResponse response,String msg){
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setStatus(401);
httpResponse.setCharacterEncoding("UTF-8");
httpResponse.setContentType("application/json;charset=UTF-8");
try {
String rj = "shiro shibai";
httpResponse.getWriter().append(rj);
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.
JWTToken.java
import org.apache.shiro.authc.AuthenticationToken;
public class JWTToken implements AuthenticationToken {
private static final long serialVersionUID = 1L;
// 祕鑰
private String token;
public JWTToken(String token) {
this.token = token;
}
@Override
public Object getPrincipal() {
return token;
}
@Override
public Object getCredentials() {
return token;
}
}
4.token的生成和解析方式,請注意網上很多方式都是無效的,我花費一天時間試驗出來的下面方式有效。
JWTUtil.java
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.lang3.StringUtils;
import java.util.Calendar;
import java.util.Date;
public class JWTUtil {
public static final String TOKEN_HEADER = "Authorization";
public static final String TOKEN_PREFIX = "Bearer ";
private static final String SECRET = "jwtsecretdemo";
public static final long EXPIRATION_REMEMBER = 24 * 60 * 60 * 7;
public static boolean verify(String token, String yhbh, String yhmm) {
Claims cl = getTokenBody(token);
String tokenYhbh = cl.get("yhbh").toString();
String tokenYhmm = cl.get("yhmm").toString();
if(StringUtils.equals(yhbh,tokenYhbh) && StringUtils.equals(yhmm,tokenYhmm)){
return true;
}else{
return false;
}
}
/**
* 從token獲取使用者編號
* @param token
* @return
*/
public static String getYhbh(String token){
try {
return getTokenBody(token).get("yhbh").toString();
}catch (Exception e){
return null;
}
}
/**
* 從token獲取使用者密碼
* @param token
* @return
*/
public static String getYhmm(String token){
try {
return getTokenBody(token).get("yhmm").toString();
}catch (Exception e){
return null;
}
}
/**
* 取出所有自定義的key,value
* */
private static Claims getTokenBody(String token){
try {
return Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token)
.getBody();
}catch (Exception e){
return null;
}
}
public static String createToken(String yhbh,String yhmm){
Date iatDate = new Date();
// expire time
Calendar nowTime = Calendar.getInstance();
//有10天有效期
nowTime.add(Calendar.DATE, 10);
Date expiresDate = nowTime.getTime();
Claims claims = Jwts.claims();
claims.put("yhbh", yhbh);
claims.put("yhmm", yhmm);
String token = Jwts.builder().setClaims(claims).setExpiration(expiresDate)
.signWith(SignatureAlgorithm.HS512, SECRET)
.compact();
return token;
}
public static void main(String[] args) {
String yhbh = "10001";
String yhmm = "111";
String token = createToken(yhbh,yhmm);
System.out.println("t="+token);
String re = getYhbh(token);
System.out.println(re);
}
}
5.
MyRealm.java
import com.szht.cbhs.business.service.user.UserService;
import com.szht.cbhs.business.vo.user.UserInfo;
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;
public class MyRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof JWTToken;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String yhbh = JWTUtil.getYhbh(principals.toString());
UserInfo user = userService.selectUserByYhbh(yhbh);
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.addRole(user.getJsbh());
return simpleAuthorizationInfo;
}
/**
* 預設使用此方法進行使用者正確與否驗證,錯誤丟擲異常即可
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
String token = (String) authenticationToken.getCredentials();
// 解密獲得username,用於和資料庫進行對比
String yhbh = JWTUtil.getYhbh(token);
if (yhbh == null) {
throw new AuthenticationException("token 無效!");
}
UserInfo user = userService.selectUserByYhbh(yhbh);
if (user == null) {
throw new AuthenticationException("使用者"+yhbh+"不存在") ;
}
if (!JWTUtil.verify(token, yhbh, user.getYhmm())) {
throw new AuthenticationException("賬戶密碼錯誤!");
}
return new SimpleAuthenticationInfo(token, token, "my_realm");
}
}
6.登入
UserController.java
import com.szht.cbhs.business.common.service.CommonDataCache;
import com.szht.cbhs.business.common.service.CommonService;
import com.szht.cbhs.business.service.user.UserService;
import com.szht.cbhs.business.vo.user.UserInfo;
import com.szht.cbhs.constant.CbhsSysConst;
import com.szht.cbhs.core.http.Result;
import com.szht.cbhs.core.msg.Message;
import com.szht.cbhs.jwt.JWTUtil;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@RestController
public class UserController {
@Autowired
private CommonService commonService;
@Autowired
private UserService userService;
@PostMapping("/login")
public Result login(@RequestBody Map<String,String> jsonmap,
HttpServletResponse response) throws UnsupportedEncodingException {
String yhbh = jsonmap.get("yhbh");
String yhmm = jsonmap.get("yhmm");
UserInfo user = userService.selectUserByYhbh(yhbh);
if (user.getYhmm().equals(yhmm)) {
String token = JWTUtil.createToken(yhbh,yhmm);
response.setHeader("token", token);
List<Message> msgs = new ArrayList<Message>();
Message msg = new Message();
msg.setMsg_info("登入成功");
msg.setMsg_type(CbhsSysConst.INFO);
msgs.add(msg);
Result rs = new Result();
rs.setSuccess(true);
rs.setMessages(msgs);
return rs;
} else {
throw new UnauthorizedException();
}
}
@RequestMapping("/401")
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public Result unauthorized() {
List<Message> msgs = new ArrayList<Message>();
Message msg = new Message();
msg.setMsg_code("401");
msg.setMsg_info("未授權");
msg.setMsg_type(CbhsSysConst.ERROR);
msgs.add(msg);
Result rs = new Result();
rs.setSuccess(false);
rs.setMessages(msgs);
return rs;
}
}
二、前端配置
Authorization裡放的是使用者密碼生成的token。
let url = '/main/pzgl/pzfh/dfhpzjs';
let data = { pzbh: this.search };
let headers = { headers: { 'Authorization': 'eyJhbGciOiJIUzUxMiJ9.eyJ5aGJoIjoiMTAwMDEiLCJ5aG1tIjoiMTExIiwiZXhwIjoxNjAzMTY1MDE1fQ.GO4aGX_Ydc5EcImexrlDjbU7qH-XjeYmRmpEGa8z5BKktCaKf2_kWO5T0dIlbISdM_4IBs0s2DWJw1Bn8dlTcw' } };
axios
.post(url, data, headers)
.then((response) => {
this.dialogDesserts = JSON.parse(JSON.stringify(response.data.data));
this.dialogDesserts.map((item, index) => {
item.id = index;
});
})
.catch((error) => {
console.log(error);
});
相關文章
- Percona Toolkit 神器全攻略(配置類)
- Linux 環境變數配置全攻略Linux變數
- 配置 containerd 映象倉庫完全攻略AI
- 阿里雲ECS伺服器配置全攻略阿里伺服器
- Shopify全攻略(3):店鋪的設計與配置
- DolphinScheduler快速上手:基於Docker Compose的安裝與配置全攻略Docker
- NFS全攻略NFS
- vue axios全攻略VueiOS
- Percona Toolkit 神器全攻略
- Dolphinscheduler Docker部署全攻略Docker
- Spring Boot Admin 2.1.0 全攻略Spring Boot
- .NET 6 史上最全攻略
- Java文件註釋全攻略Java
- Angular 4.0 內建指令全攻略Angular
- MySQL-索引優化全攻略MySql索引優化
- 程式設計師跳槽全攻略程式設計師
- Jack's側方移位全攻略
- python處理操作pdf全攻略Python
- Percona Toolkit 神器全攻略(效能類)
- Webpack4新手完全攻略Web
- Android依賴匯入全攻略Android
- Oracle 12c RMAN全攻略Oracle
- Ambari HDP叢集搭建全攻略
- Spring Cloud Consul 之Greenwich版本全攻略SpringCloud
- Hibernate Validator校驗引數全攻略
- Spring Cloud Sleuth 之Greenwich版本全攻略SpringCloud
- Percona Toolkit 神器全攻略(複製類)
- Percona Toolkit 神器全攻略(系統類)
- Percona Toolkit 神器全攻略(監控類)
- Percona Toolkit 神器全攻略(實用類)
- VSCode外掛開發全攻略(二)HelloWordVSCode
- VSCode外掛開發全攻略(七)WebViewVSCodeWebView
- H5 移動除錯全攻略H5除錯
- 開源評論系統 Isso 全攻略
- Android P 劉海屏適配全攻略Android
- 少女風vue元件庫製作全攻略~~Vue元件
- 2019 SEO 新趨勢,全攻略 - Whoops SEOOOP
- 遊戲全球發行Soft Launch全攻略遊戲