1 關於Shiro前端
Apache Shiro 是一個Java的安全框架,主要有三個核心的組件:web
Subject:指當前的操做用戶。spring
SecurityManager:安全管理器,Shiro經過它來管理內部組件。數據庫
Realm:用於權限的驗證,須要本身實現。apache
2 步驟瀏覽器
首先引入Shiro的maven:安全
<!--整合shiro--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-web-starter</artifactId> <version>1.4.0</version> </dependency>cookie |
在application.properties裏添加Shrio的配置信息:session
#1.第一行表示是否容許將sessionld 放到cookie 中 shiro.sessionManager.sessionIdCookieEnabled=true #2第二行表示是否容許將sessionld 放到Url地址攔中 shiro.sessionManager.sessionIdUrlRewritingEnabled=true #3.第三行表示訪問未獲受權的頁面時,默認的跳轉路徑 shiro.unauthorizedUrl=/login #4.第四行表示開啓shiro shiro.web.enabled=true #5.第五行表示登陸成功的跳轉頁面 shiro.successUrl=/index #6.第六行表示登陸頁面 shiro.loginUrl=/doLoginapp |
須要實現一個Realme類,繼承AuthorizingRealm,並實現它的方法,其中一個是AuthorizationInfo,須要本身寫對於權限的管理,另外一個是AuthenticationInfo,這裏是寫登陸驗證。具體代碼以下:
public class UserRealm extends AuthorizingRealm { @Autowired private StudentServiceImpl studentService; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { return null; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { String username = authenticationToken.getPrincipal().toString(); Optional<Student> studentOptional = studentService.findStudentBySno(username); if (studentOptional.isPresent()) { Student student = studentOptional.get(); return new SimpleAuthenticationInfo(username, student.getPassword(), ByteSource.Util.bytes(username), getName()); } throw new UnknownAccountException("不存在"); } } |
登陸驗證是先獲取到username,而後查到該用戶的相關信息,若是不存在則返回一個UnknownAccountException異常。存在則返回一個SimpleAuthenticationInfo,參數是username、數據庫查到的密碼、還有鹽值和用戶名。接着須要配置Shiro:
@Configuration public class ShiroConfig { @Bean UserRealm userRealm() { return new UserRealm(); } @Bean DefaultWebSecurityManager securityManager() { DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(); defaultWebSecurityManager.setRealm(userRealm()); return defaultWebSecurityManager; } @Bean ShiroFilterChainDefinition shiroFilterChainDefinition() { DefaultShiroFilterChainDefinition defaultShiroFilterChainDefinition = new DefaultShiroFilterChainDefinition(); defaultShiroFilterChainDefinition.addPathDefinition("/doLogin", "anon"); defaultShiroFilterChainDefinition.addPathDefinition("/**", "authc"); return defaultShiroFilterChainDefinition; } } |
將剛剛的UserReaml交給SecurityManager進行管理。而且設置過濾器,好比哪些接口是須要登陸後或者某種權限才能訪問的。其中 anon 表示匿名即遊客就能訪問,這裏設置了登陸接口。authc是須要登陸驗證後才能訪問。除了這兩種還有其餘:
authcBasic、logout、noSessionCreation、perms、port、rest、roles、ssl、user。
若是用戶開啓了RememberMe,則當用戶關閉瀏覽器,下次訪問時,再也不是authc,而是user。由於authc是須要從新認證的。User就表示該用戶曾經被Shiro記住過。
接下來寫LoginController:
@PostMapping("/doLogin") public Result<Object> doLogin(@RequestBody UserToken userToken) { Subject subject = SecurityUtils.getSubject(); String pwd = ShiroKit.mds(String.valueOf(userToken.getPassword()), userToken.getUsername()); UsernamePasswordToken token = new UsernamePasswordToken(userToken.getUsername(), pwd); String sessionId = (String) subject.getSession().getId(); try { subject.login(token); Map<String, String> map = new HashMap<String, String>(); map.put("sessionId", sessionId); map.put("username", userToken.getUsername()); return common.SUCCESS(map); } catch (Exception e) { return common.ERROR(codeEnum.getERR_PWD(), "用戶名或密碼錯誤", ""); } } |
由於密碼不是明文儲存在數據庫中的,因此這裏採用了MD5加密,沒有使用Shiro的加密方式。須要將獲取到的密碼進行再次加密後和數據庫進行比對驗證。
加密方式:
public class ShiroKit { public static String mds(String password, String salt) { return new Md5Hash(password, salt, 1).toHex();// 加密一次 } } |
這裏subject.login則會調用UserReaml,將用戶名和加密後的密碼傳過去進行驗證。若是有錯誤,好比密碼不正確或者用戶不存在就給前端返回一個用戶名或密碼不正確的提示。
登出:
@GetMapping("/logout") public Result logout() { SecurityUtils.getSubject().logout(); return common.SUCCESS(""); } |
3 總結
這裏只是簡單運用了shiro實現了登陸驗證。沒有去分析源碼,有須要的朋友能夠自行去官方查閱。
END
編 輯 | 王文星
責 編 | 劉玉江
能力越強,責任越大。實事求是,嚴謹細緻。
——where2go 團隊