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 团队
