目錄
前言:
概念:
源碼:
步驟:
(1) 首先我準備一個資料庫 shiro_demo 并且建立了一張bos_user 的表
(2)在pom 檔案中引入 Shiro 1.5.2 的jar 包
(3) 配置檔案中配置資料連接配接資訊
(4)編寫Shiro 的配置類
(5) 異常處理類 NyExceptionHandler
(6) MyFormAuthenticationFilter
(7) MyHashedCredentialsMatcher
(8) MyRealm
(9) MySessionManager
(10) MyUserNamePasswordToken
(11)RedisSessionDao
(12)整個項目路徑是這樣的!
測試:
(1) 我編寫了倆個接口:一個是test 一個是vueLogin
(2)業務邏輯類如下:
(3)在網頁上通路一下:http://localhost:8006/test/ 滑鼠一回車顯示的是未登入
參考文章:
前言:
Shiro 安全架構是目前為止作為登入注冊最常用的架構,因為它十分的強大簡單,提供了認證,授權 ,加密和會話管理等功能。
我們項目的登入功能就內建了Shiro ,如果你也對Shiro感興趣,一起随着小編看下去吧!
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TTq1EendUYwQWbihmUzwEMW1mY1RzRapnTtxkb5ckYplTeMZTTINGMShUYfRHelRHLwEzX39GZhh2css2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xyayFWbyVGdhd3LcV2Zh1Wa9M3clN2byBXLzN3btg3Pml2ZuUTM1ATMzkDM2ADNwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.gif)
Shiro 官網 :http://shiro.apache.org/
Apache Shiro 1.5.2是目前的穩定版本(Java 1.8+ JVM)。
概念:
圖引自:戳這
最簡單的Shiro應用:
1.應用代碼通過Subject 來進行認證和授權,而Subject 又委托給SecurityManager
2.我們需要給Shiro的SecurityManager 注入Realm,進而讓SecurityManager能得到合法的使用者及其權限進行判斷。
三個核心元件:
Subject, SecurityManager 和 Realms.
①Subject:即“目前操作使用者”。但是,在Shiro中,Subject這一概念并不僅僅指人,也可以是第三方程序、背景帳戶(Daemon Account)或其他類似事物。它僅僅意味着“目前跟軟體互動的東西”。但考慮到大多數目的和用途,你可以把它認為是Shiro的“使用者”概念。Subject代表了目前使用者的安全操作,SecurityManager則管理所有使用者的安全操作。
②SecurityManager:它是Shiro架構的核心,典型的Facade模式,Shiro通過SecurityManager來管理内部元件執行個體,并通過它來提供安全管理的各種服務。
③Realm: Realm充當了Shiro與應用安全資料間的“橋梁”或者“連接配接器”。也就是說,當對使用者執行認證(登入)和授權(通路控制)驗證時,Shiro會從應用配置的Realm中查找使用者及其權限資訊。
原文:https://www.jianshu.com/p/6abc22ec3cb8
Shiro登入驗證的流程:
- 調用subject.login() 方法進行登入,其會自動委托給securityManager.login方法進行登入。
- 通過SecurityManager進入 realm 中進行判斷權限和登入認證
- 在 realm 中調用dao 層查詢資料庫
- 擷取使用者資料
- realm 包裝原始資料傳入SecurityManager。通過SecurityManager調用認證方法,根據login 傳入的 token 和 realm 傳回的使用者真實資料進行比對是否正确。如果不正确抛出各種異常,比如未知使用者異常,密碼錯誤,登入次數過多異常等。
- 根據傳回的異常,各種 try..catch..,沒有異常傳回,則表示登入成功,反之傳回前端 catch 結果。
Shiro 登入認證過程詳解:https://blog.csdn.net/caoyang0105/article/details/82769293
1. Shiro認證目的就是判斷使用者的賬号密碼是否正确之類的,授權的作用嘛,簡單的解釋就是給使用者賦予相應的權限。
2. 判斷一個使用者有沒有權限通路,無非是攔截URL能否通路,分為以下幾個操作
- 判斷目前URL是否需要攔截,不需要則放行,需要則進入下一步
- 判斷使用者是否已登陸,有則下一步,無則抛出401未認證
- 從資源表/權限表讀取目前登陸使用者的可通路位址,進入下一步
- 判斷是否包含使用者目前通路的位址,有則放行,無則抛出403無權限
源碼:
連結:https://pan.baidu.com/s/1DxfE-Azg2RZrSS6sDlP59Q
提取碼:01z2
同時代碼也放入github中,網址:https://github.com/tanghh0410/csdn_blog.git
步驟:
(1) 首先我準備一個資料庫 shiro_demo 并且建立了一張bos_user 的表
(2)在pom 檔案中引入 Shiro 1.5.2 的jar 包
<!-- shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.5.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.5.2</version>
</dependency>
(3) 配置檔案中配置資料連接配接資訊
server.port=8006
# MySQL Database
spring.datasource.url=jdbc:mysql://localhost:3306/shiro_demo?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone = GMT
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
shiro.jessionid=sessionId
(4)編寫Shiro 的配置類
package com.example.shiro.config;
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.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.web.servlet.HandlerExceptionResolver;
import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;
/**
*
*/
@Configuration
public class ShiroConfig {
@Value("${shiro.jessionid}")
private String jessionId;
@Value("${spring.datasource.url}")
public String url;
@Value("${spring.datasource.username}")
public String username;
@Value("${spring.datasource.password}")
public String password;
@Value("${spring.datasource.driver-class-name}")
public String driver;
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
/* 自定義filter注冊 */
Map<String, Filter> filters = shiroFilterFactoryBean.getFilters();
filters.put("myAuthc", new MyFormAuthenticationFilter());
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
//注意過濾器配置順序 不能颠倒
//配置退出 過濾器,其中的具體的退出代碼Shiro已經替我們實作了,登出後跳轉配置的loginUrl
// 配置不會被攔截的連結 順序判斷
filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap.put("/vueLogin", "anon");
filterChainDefinitionMap.put("/**", "myAuthc");
//轉應配置shiro預設登入界面位址,前後端分離中登入界面跳由前端路由控制,背景僅傳回json資料
shiroFilterFactoryBean.setLoginUrl("/unauth");
//未授權界面;
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public MyRealm realm() {
MyRealm myRealm = new MyRealm();
//驗證
MyHashedCredentialsMatcher myHashedCredentialsMatcher = new MyHashedCredentialsMatcher();
myHashedCredentialsMatcher.setHashAlgorithmName("MD5");
myRealm.setCredentialsMatcher(myHashedCredentialsMatcher);
return myRealm;
}
// @Bean
// public JdbcRealm jdbcRealm() {
// JdbcRealm jdbcRealm = new JdbcRealm();
// jdbcRealm.setPermissionsLookupEnabled(true);//為了查詢權限表,要開啟權限查詢
// jdbcRealm.setDataSource(datasource());
// return jdbcRealm;
// }
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm());
// 自定義緩存實作 使用redis
// 自定義session管理
securityManager.setSessionManager(defaultWebSessionManager());
return securityManager;
}
@Bean
public RedisSessionDao getRedisSessionDao() {
return new RedisSessionDao();
}
/**
* @return
* @see DefaultWebSessionManager
*/
@Bean(name = "sessionManager")
public DefaultWebSessionManager defaultWebSessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
//sessionManager.setCacheManager(cacheManager());
//12小時
sessionManager.setGlobalSessionTimeout(43200000);
sessionManager.setDeleteInvalidSessions(true);
//關鍵在這裡
sessionManager.setSessionDAO(getRedisSessionDao());
sessionManager.setSessionValidationSchedulerEnabled(true);
sessionManager.setDeleteInvalidSessions(true);
sessionManager.setSessionIdCookie(getSessionIdCookie());
return sessionManager;
}
/**
* 給shiro的sessionId預設的JSSESSIONID名字改掉
*
* @return
*/
@Bean(name = "sessionIdCookie")
public SimpleCookie getSessionIdCookie() {
SimpleCookie simpleCookie = new SimpleCookie(jessionId);
return simpleCookie;
}
/**
* 自定義sessionManager
*
* @return
*/
@Bean
public SessionManager sessionManager() {
MySessionManager mySessionManager = new MySessionManager();
return mySessionManager;
}
/**
* 開啟aop注解支援
*
* @param
* @return
*/
@Bean(name = "lifecycleBeanPostProcessor")
public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
/**
* 開啟Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP掃描使用Shiro注解的類,并在必要時進行安全邏輯驗證
* 配置以下兩個bean(DefaultAdvisorAutoProxyCreator(可選)和AuthorizationAttributeSourceAdvisor)即可實作此功能
*
* @return
*/
@Bean
@DependsOn({"lifecycleBeanPostProcessor"})
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
return authorizationAttributeSourceAdvisor;
}
@Bean(name = "exceptionHandler")
public HandlerExceptionResolver handlerExceptionResolver() {
return new MyExceptionHandler();
}
}
(5) 異常處理類 NyExceptionHandler
package com.example.shiro.config;
import com.alibaba.fastjson.support.spring.FastJsonJsonView;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
/**
* @Author: tanghh18
* @Date: 2020/4/6 11:28
*/
public class MyExceptionHandler implements HandlerExceptionResolver {
private static Logger logger = LoggerFactory.getLogger(MyExceptionHandler.class);
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception ex) {
ModelAndView mv = new ModelAndView();
FastJsonJsonView view = new FastJsonJsonView();
Map map = new HashMap();
if (ex instanceof UnauthenticatedException|| ex instanceof IncorrectCredentialsException || ex instanceof AuthenticationException) {
map.put("msg", "使用者名或密碼錯誤");
} else if (ex instanceof UnauthorizedException) {
map.put("msg", "無權限");
} else {
map.put("msg", ex.getMessage());
logger.info(ex.getMessage());
ex.printStackTrace();
}
view.setAttributesMap(map);
mv.setView(view);
return mv;
}
}
(6) MyFormAuthenticationFilter
package com.example.shiro.config;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.springframework.context.annotation.Bean;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* @Author: tanghh18
* @Date: 2020/4/6 11:29
*/
public class MyFormAuthenticationFilter extends FormAuthenticationFilter {
@Override
protected AuthenticationToken createToken(String username, String password, ServletRequest request, ServletResponse response) {
boolean rememberMe = isRememberMe(request);
String host = getHost(request);
String loginType = "password";
if(request.getParameter("loginType")!=null && !"".equals(request.getParameter("loginType").trim())){
loginType = request.getParameter("loginType");
}
return new MyUsernamePasswordToken(username, password,loginType,rememberMe,host);
}
}
(7) MyHashedCredentialsMatcher
package com.example.shiro.config;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
/**
* @Author: tanghh18
* @Date: 2020/4/6 11:30
*/
public class MyHashedCredentialsMatcher extends HashedCredentialsMatcher {
@Override public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
MyUsernamePasswordToken mupt = (MyUsernamePasswordToken)token;
if ("nopassword".equals(mupt.getLoginType())) {
return true;
}else {
return super.doCredentialsMatch(token, info);
}
}
}
(8) MyRealm
package com.example.shiro.config;
import com.example.model.BosUserModel;
import com.example.service.BosUserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
/**
* @Author: tanghh18
* @Date: 2020/4/6 11:34
*/
public class MyRealm extends AuthorizingRealm {
@Autowired
BosUserService bosUserService;
/**
* 授權
*
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
/**
* 認證
*
* @param arg0
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
//将父類的AuthenticationToken強轉為UsernamePasswordToken(因為需要調用UsernamePasswordToken的方法)
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) arg0;
//擷取使用者名
String uname = usernamePasswordToken.getUsername();
//模拟通過資料庫查詢到使用者名的密碼
BosUserModel user = bosUserService.findUserModelByName(uname);
//認證資訊(參數填寫的是使用者輸入的使用者名和資料庫查詢的密碼)
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(uname, user.getPassword(), getName());
return info;
}
}
(9) MySessionManager
package com.example.shiro.config;
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;
/**
* @Author: tanghh18
* @Date: 2020/4/6 14:00
*/
public class MySessionManager extends DefaultWebSessionManager {
private static final String AUTHORIZATION = "Authorization";
private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";
public MySessionManager() {
super();
}
@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);
}
}
}
(10) MyUserNamePasswordToken
package com.example.shiro.config;
import org.apache.shiro.authc.UsernamePasswordToken;
/**
* @Author: tanghh18
* @Date: 2020/4/6 14:00
*/
public class MyUsernamePasswordToken extends UsernamePasswordToken {
/**
* 免密登入/賬号密碼登入
*/
private String loginType;
public MyUsernamePasswordToken() {
super();
}
/**
* 賬号密碼登入
* @param username
* @param password
* @param loginType
* @param rememberMe
* @param host
*/
public MyUsernamePasswordToken(String username, String password, String loginType, boolean rememberMe, String host) {
super(username, password, rememberMe, host);
this.loginType = loginType;
}
/**
* 免密登入
* @param username
*/
public MyUsernamePasswordToken(String username) {
super(username, "", false, null);
this.loginType = "nopassword";
}
public MyUsernamePasswordToken(String username, String password) {
super(username, password, false, null);
this.loginType ="password";
}
public String getLoginType() {
return loginType;
}
public void setLoginType(String loginType) {
this.loginType = loginType;
}
}
(11)RedisSessionDao
package com.example.shiro.config;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Service;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* Created by Administrator on 2018/7/31.
*/
@Service
public class RedisSessionDao extends AbstractSessionDAO {
/**
* Session逾時時間,機關為毫秒
*/
private static Logger logger = LoggerFactory.getLogger(RedisSessionDao.class);
private long expireTime = 30*60*1000;
/**
* Redis操作類,對這個使用不熟悉的,可以參考前面的部落格
*/
@Autowired
private RedisTemplate redisTemplate;
public RedisSessionDao() {
super();
}
public RedisSessionDao(long expireTime, RedisTemplate redisTemplate) {
super();
this.expireTime = expireTime;
//Long類型不可以會出現異常資訊;
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(redisSerializer);
redisTemplate.setHashKeySerializer(redisSerializer);
this.redisTemplate = redisTemplate;
}
/**
* 更新session
* @param session
* @throws UnknownSessionException
*/
@Override
public void update(Session session) throws UnknownSessionException {
if (session == null || session.getId() == null) {
return;
}
session.setTimeout(expireTime);
redisTemplate.opsForValue().set(session.getId(), session, expireTime, TimeUnit.MILLISECONDS);
}
/**
* 删除session
* @param session
*/
@Override
public void delete(Session session) {
if (null == session) {
return;
}
redisTemplate.opsForValue().getOperations().delete(session.getId());
}
/**
* // 擷取活躍的session,可以用來統計線上人數,如果要實作這個功能,
* 可以在将session加入redis時指定一個session字首,統計的時候則使用keys("session-prefix*")的方式來模糊查找redis中所有的session集合
* @param
* @return
*/
@Override
public Collection<Session> getActiveSessions() {
Set keys = redisTemplate.keys("*");
Collection<Session> activeSessions = new ArrayList<>();
for (Object o:keys){
String sessionId = o.toString();
if(sessionId.equals("SuiteTicket") || sessionId.equals("suite_access_token")){
continue;
}
Session session = (Session) redisTemplate.opsForValue().get(sessionId);
activeSessions.add(session);
}
return activeSessions;
}
/**
* 加入session
* @param session
* @return
*/
@Override
protected Serializable doCreate(Session session) {
Serializable sessionId = this.generateSessionId(session);
this.assignSessionId(session, sessionId);
//Long類型不可以會出現異常資訊;
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(redisSerializer);
redisTemplate.setHashKeySerializer(redisSerializer);
redisTemplate.opsForValue().set(session.getId(), session, expireTime, TimeUnit.MILLISECONDS);
return sessionId;
}
/**
* 讀取session
* @param sessionId
* @return
*/
@Override
protected Session doReadSession(Serializable sessionId) {
if (sessionId == null) {
return null;
}
return (Session) redisTemplate.opsForValue().get(sessionId);
}
public long getExpireTime() {
return expireTime;
}
public void setExpireTime(long expireTime) {
this.expireTime = expireTime;
}
public RedisTemplate getRedisTemplate() {
return redisTemplate;
}
public void setRedisTemplate(RedisTemplate redisTemplate) {
//Long類型不可以會出現異常資訊;
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(redisSerializer);
redisTemplate.setHashKeySerializer(redisSerializer);
this.redisTemplate = redisTemplate;
}
}
(12)整個項目路徑是這樣的!
測試:
(1) 我編寫了倆個接口:一個是test 一個是vueLogin
package com.example.controller;
import com.example.model.BosUserModel;
import com.example.service.BosUserService;
import com.example.shiro.config.MyUsernamePasswordToken;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;
/**
* @Author: wwc
* @Date: 2019/3/6 14:26
* @Version 1.0
*/
@RestController
public class ShiroController {
@Autowired
private BosUserService bosUserService;
@GetMapping(value = "/test")
public void test(){
System.out.println("這是測試接口-----");
}
/**
* 登入方法
*
* @return
*/
@GetMapping(value = "/vueLogin")
public void login(HttpSession session) throws Exception {
//shiro登入,普通的使用者名和密碼登入
Subject subject = SecurityUtils.getSubject();
BosUserModel user = new BosUserModel();
user.setId(1);
user.setUserName("soup_tang");
user.setPassword("1");
// user.setPassword("c4ca4238a0b923820dcc509a6f75849b");
UsernamePasswordToken token = new MyUsernamePasswordToken(user.getUserName(), user.getPassword());
subject.login(token);
//使用者資料儲存到session裡
BosUserModel bosUserModel = bosUserService.findUserModelByName(user.getUserName());
if(bosUserModel!=null){
System.out.println("登入成功");
session.setAttribute("user", bosUserModel);
}else{
System.out.println("登入失敗");
}
}
/**
* 未登入,shiro應重定向到登入界面,此處傳回未登入狀态資訊由前端控制跳轉頁面
*
* @return
*/
@RequestMapping(value = "/unauth")
@ResponseBody
public Object unauth() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("msg", "未登入");
return map;
}
}
(2)業務邏輯類如下:
package com.example.service.impl;
import com.example.model.BosUserModel;
import com.example.service.BosUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.Map;
/**
* @Author tanghh
* @Date 2020/4/6 10:49
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class BosUserServiceImpl implements BosUserService {
@Autowired
private JdbcTemplate jdbcTemplate;
/**
* 根據名字查詢使用者資料
* @param name
* @return
*/
@Override
public BosUserModel findUserModelByName(String name) {
String sql = "select * from bos_user where user_name=?";
Map map = new HashMap<>();
map.put("name",name);
BosUserModel userModel = this.jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<BosUserModel>(BosUserModel.class),name);
return userModel;
}
}
(3)在網頁上通路一下:http://localhost:8006/test/ 滑鼠一回車顯示的是未登入
(4)在網頁上通路一下:http://localhost:8006/vueLogin/
控制台列印語句:
一個接口test 被攔截了 , 一個vueLogin沒有被攔截,那麼是通過什麼方法被攔截的呢?答案在:ShiroConfig類。
我在下面這個類的位置 配置了 vueLogin 不被攔截。
還有一個問題就是:
可以看到下面這張圖我将 密碼寫成的是md5加密的值,這個時候會出現什麼問題呢,往下看:
在我的 MyExceptionHandler 類開始報異常了。
百度一下結果 是因為傳過來的密碼無法将值hash ,後面将代碼改過來就可以了,因為我在下面這個方法中寫了将密碼轉化成md5
使用: user.setPassword("1");
參考文章:
Shiro學習目錄貼:https://www.iteye.com/blog/jinnianshilongnian-2018398