范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

从零开始,手打一个权限管理系统(第四章登录(中))

  前言
  这章我们来整合JWT,实现一个自定义的登录一、认证流程
  我先捋一下认证的流程,方便我们后面写自定义登录
  核心的类就几个,分别是:
  Authentication:用户认证
  AbstractAuthenticationProcessingFilter:认证处理拦截器
  AuthenticationManager:处理认证
  AuthenticationProvider:具体做认证的
  UserDetailsService:获取用户信息
  AuthenticationSuccessHandler:认证成功处理器
  AuthenticationFailureHandler:认证失败处理器
  我们自定义登录其实也是就是根据我们自己的需求重写这几个类。二、自定义登录
  认证和授权相关的都放在base-security这个目录,方便我们后面做扩展;
  自定义的这些类,其实就是仿照以UsernamePassword开头的类来写的,部分代码其实都是一样的。
  1、自定义用户认证的对象JwtUserpublic class JwtUser extends User { /** * 用户ID */ @Getter private String id; /** * 机构ID */ @Getter private String orgId;  public JwtUser(String id, String orgId, String username, String password, Collection<? extends GrantedAuthority> authorities) { super(username, password, authorities); this.id = id; this.orgId = orgId; } }
  2、自定义JwtAuthenticationToken
  代码其实跟UsernamePasswordAuthenticationToken差不多public class JwtAuthenticationToken extends AbstractAuthenticationToken { /** * 登录信息 */ private final Object principal; /** * 凭证 */ private final Object credentials; /** * 创建已认证的授权 * * @param authorities * @param principal * @param credentials */ public JwtAuthenticationToken(Collection<? extends GrantedAuthority> authorities, Object principal, Object credentials) { super(authorities); this.principal = principal; this.credentials = credentials; super.setAuthenticated(true); } /** * 创建未认证的授权 * * @param principal * @param credentials */ public JwtAuthenticationToken(Object principal, Object credentials) { //因为刚开始并没有认证,因此用户没有任何权限,并且设置没有认证的信息(setAuthenticated(false)) super(null); this.principal = principal; this.credentials = credentials; super.setAuthenticated(false); } @Override public Object getCredentials() { return this.credentials; } @Override public Object getPrincipal() { return this.principal; } }
  3、自定义认证拦截器JwtAuthenticationFilter
  这个类也是仿照UsernamePasswordAuthenticationFilter来实现的/** * 这个代码完全是仿照UsernamePasswordAuthenticationFilter来写的 * {@link UsernamePasswordAuthenticationFilter} */ public class JwtAuthenticationFilter extends AbstractAuthenticationProcessingFilter { private static final AntPathRequestMatcher DEFAULT_ANT_PATH_REQUEST_MATCHER = new AntPathRequestMatcher("/login", "POST"); private String usernameParameter = "username"; private String passwordParameter = "password"; public JwtAuthenticationFilter() { super(DEFAULT_ANT_PATH_REQUEST_MATCHER); } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { if (!request.getMethod().equals(HttpMethod.POST.name())) { throw new AuthenticationServiceException( "Authentication method not supported: " + request.getMethod()); } String username = request.getParameter(this.usernameParameter); username = (username != null) ? username.trim() : ""; String password = request.getParameter(this.passwordParameter); password = (password != null) ? password : ""; //创建未认证的token JwtAuthenticationToken authRequest = new JwtAuthenticationToken(username, password); //认证详情写入到凭着 authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); return this.getAuthenticationManager().authenticate(authRequest); } }
  4、自定义认证处理器JwtAuthenticationProvider
  大部分的代码也来自AbstractUserDetailsAuthenticationProvider和DaoAuthenticationProvider@Slf4j @Component public class JwtAuthenticationProvider implements AuthenticationProvider { private MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor(); @Getter @Setter private UserDetailsService userDetailsService; @Getter @Setter private PasswordEncoder passwordEncoder; public JwtAuthenticationProvider() { } @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { UserDetails user = userDetailsService.loadUserByUsername(authentication.getName()); JwtAuthenticationToken jwtAuthenticationToken = (JwtAuthenticationToken) authentication; additionalAuthenticationChecks(user, jwtAuthenticationToken); //构建已认证的authenticatedToken JwtAuthenticationToken result = new JwtAuthenticationToken(jwtAuthenticationToken.getAuthorities(), user, jwtAuthenticationToken.getCredentials()); result.setDetails(authentication.getDetails()); log.debug("Authenticated user"); return result; } @Override public boolean supports(Class<?> authentication) { return (JwtAuthenticationToken.class.isAssignableFrom(authentication)); } /** * 直接拷贝的DaoAuthenticationProvider里面的同名方法 * @param userDetails * @param authentication * @throws AuthenticationException */ private void additionalAuthenticationChecks(UserDetails userDetails, JwtAuthenticationToken authentication) throws AuthenticationException { if (authentication.getCredentials() == null) { log.debug("Failed to authenticate since no credentials provided"); throw new BadCredentialsException(this.messages .getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); } String presentedPassword = authentication.getCredentials().toString(); if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) { log.debug("Failed to authenticate since password does not match stored value"); throw new BadCredentialsException(this.messages .getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); } } }
  5、自定义认证成功和失败处理类
  默认情况下,认证成功和失败都是跳转到别的页面,我们改为返回一个json对象
  5.1、认证失败JwtAuthenticationFailureHandler@Slf4j @Component public class JwtAuthenticationFailureHandler implements AuthenticationFailureHandler { @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { log.info("登录失败:{}", exception.getLocalizedMessage()); response.setContentType(MediaType.APPLICATION_JSON_VALUE); response.getWriter().write(exception.getLocalizedMessage()); response.getWriter().flush(); response.getWriter().close(); } }
  5.2、认证成功JwtAuthenticationSuccessHandler
  认证成功后我们需要返回一个token,所以我们需要一个Jwt的工具类JWTUtils@Slf4j @Component @AllArgsConstructor public class JWTUtils { private final JwtProperties jwtProperties; public static final String ID = "id"; public static final String ORGID = "orgId"; public static final String USERNAME = "username"; public static final String AUTHORITIES = "authorities"; /** * 生成token * * @param jwtUser * @return */ public String createToken(JwtUser jwtUser) { // 签名算法 ,将对token进行签名 SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(jwtProperties.getSecret()); Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName()); Map claims = Maps.newHashMap(); claims.put(ID, jwtUser.getId()); claims.put(ORGID, jwtUser.getOrgId()); claims.put(USERNAME, jwtUser.getUsername()); List list = jwtUser.getAuthorities().stream().collect(Collectors.toList()); List stringList = list.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()); claims.put(AUTHORITIES, JSONUtil.toJsonStr(stringList)); return Jwts .builder() .setHeaderParam("typ", "JWT") .setClaims(claims) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + jwtProperties.getExpire() * 60 * 60 * 1000)) .signWith(signatureAlgorithm, signingKey).compact(); } /** * 检查token是否有效 * * @param token the token * @return the claims */ public Claims getClaimsFromToken(String token) { try { return Jwts.parser().setSigningKey(jwtProperties.getSecret()).parseClaimsJws(token).getBody(); } catch (Exception e) { log.error("验证token出错:{}", e.getMessage()); return null; } } /** * 判断是否过期 * * @param claims * @return */ public boolean isTokenExpired(Claims claims) { return claims.getExpiration().before(new Date()); } /** * true 无效 * false 有效 * * @param token * @return */ public boolean checkToken(String token) { Claims claims = getClaimsFromToken(token); if (claims != null) { return isTokenExpired(claims); } return true; } }
  这里面的jwtProperties主要用来动态配置token秘钥和有效期,所以需要在spring.factories配置@Slf4j @Component public class JwtAuthenticationSuccessHandler implements AuthenticationSuccessHandler { @Autowired private JWTUtils jwtUtils; @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { //从authentication中获取用户信息 final JwtUser userDetail = (JwtUser) authentication.getPrincipal(); log.info("{}:登录成功", userDetail.getUsername()); response.setContentType(MediaType.APPLICATION_JSON_VALUE); String token = jwtUtils.createToken(userDetail); response.getWriter().write(token); response.getWriter().flush(); response.getWriter().close(); } }
  6、安全配置@EnableWebSecurity public class SpringSecurityConfigurer { private final JwtUserDetailsService jwtUserDetailsService; private final JwtAuthenticationSuccessHandler jwtAuthenticationSuccessHandle; private final JwtAuthenticationFailureHandler jwtAuthenticationFailureHandler; public SpringSecurityConfigurer(JwtUserDetailsService jwtUserDetailsService, JwtAuthenticationSuccessHandler jwtAuthenticationSuccessHandle, JwtAuthenticationFailureHandler jwtAuthenticationFailureHandler) { this.jwtUserDetailsService = jwtUserDetailsService; this.jwtAuthenticationSuccessHandle = jwtAuthenticationSuccessHandle; this.jwtAuthenticationFailureHandler = jwtAuthenticationFailureHandler; } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http //禁用表单登录 .formLogin().disable() .authorizeRequests((authorize) -> authorize // 这里需要将登录页面放行,permitAll()表示不再拦截, .antMatchers("/upms/login/**").permitAll() // 所有请求都要验证 .anyRequest().authenticated()) // 关闭csrf .csrf((csrf) -> csrf.disable()) //禁用session,JWT校验不需要session .sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); return http.build(); } @Bean JwtAuthenticationFilter jwtAuthenticationFilter() { JwtAuthenticationFilter jwtAuthenticationFilter = new JwtAuthenticationFilter(); jwtAuthenticationFilter.setAuthenticationManager(authenticationManager()); jwtAuthenticationFilter.setAuthenticationSuccessHandler(jwtAuthenticationSuccessHandle); jwtAuthenticationFilter.setAuthenticationFailureHandler(jwtAuthenticationFailureHandler); return jwtAuthenticationFilter; } @Bean JwtAuthenticationProvider jwtAuthenticationProvider() { JwtAuthenticationProvider jwtAuthenticationProvider = new JwtAuthenticationProvider(); //设置userDetailsService jwtAuthenticationProvider.setUserDetailsService(jwtUserDetailsService); //设置加密算法 jwtAuthenticationProvider.setPasswordEncoder(passwordEncoder()); return jwtAuthenticationProvider; } /** * 自定义的认证处理器 */ @Bean public AuthenticationManager authenticationManager() { return new ProviderManager(jwtAuthenticationProvider()); } /** * 指定加解密算法 * * @return */ @Bean PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } 三、编译运行
  经过一系列的调试修改后,启动项目,模拟登录请求,看到如下界面就表示成功了。
  当前版本tag:1.0.3
  代码仓库四、 体验地址
  后台数据库只给了部分权限,报错属于正常!
  想学的老铁给点点关注吧!!!
  我是阿咕噜,一个从互联网慢慢上岸的程序员,如果喜欢我的文章,记得帮忙点个赞哟,谢谢!

年龄30女生,如何把普通白衬衫穿出时髦的日系美式减龄范儿?白衬衫这个单品,实在是常见的不能再常见了。包括我在内,衣柜里标准领小立领的各式各样的衬衫没有十件也有八件。今天就拿实穿性最强也最常见的普通翻领的白衬衫来讲讲。看完文章,无论年龄几何软件大国沦为阴谋国!严禁中国200多个软件后,国家排名直降据印度传媒此前的报道,计算机技术在上个世纪冷战完结时发展急速。印度政府看见了在这一新兴产业展开大规模融资的机遇,并拨款规划了许多专科学院和其他基础教育机关早在冷战完结之后,印度政府我都已经躺平了,深信服,你还想让我怎样?在内卷愈演愈烈的当下,职场人即便想要被动式躺平也不可以,因为老板们正在通过行为分析系统监控着你。而这也是连日来,深信服科技股份有限公司(以下简称深信服,300454。SZ)深陷舆论雪容融正式上岗了随着闭幕式上奥运火炬的熄灭,北京第24届冬季奥运会也随之完美收官。中国队以9金,4银,2铜,位列奖牌榜第三名,历史上首次进入奖牌榜前三,金牌获得数也是目前历史最多的一届,感谢我们参张嘉益受不了前妻杜珺的嫌弃,余生不辜负帮我戒ampampquot麻瘾ampampquot的王海燕如果不是我爸爸,你张嘉益到今天什么都不是。那时的张嘉益,无论如何都想不到这句刺耳又伤人自尊的话,是从自己妻子杜珺的嘴里说出来的。这句话就像是一把利刃,把张嘉益那仅存的尊严杀的片甲不人世间揭开兄弟姐妹关系遮羞布父母不在,兄弟姐妹也会渐行渐远电视剧人世间正在热映,这部电视剧集结了雷佳音殷桃宋佳丁勇岱和萨日娜等众多老戏骨,可谓老戏骨云集,在线飙戏。这部电视剧从播出之初就备受期待,不仅是因为观众可以一饱眼福,看到老戏骨演技OA自动化办公管理系统(javaLayuiSSMMavenmysqlJSPhtml)一项目运行环境配置Jdk1。8Tomcat8。5mysqlEclispe(IntelliJIDEA,Eclispe,MyEclispe,Sts都支持)项目技术JSPSpringSp雷丁芒果2022款,外观小巧,轴距达2440mm,售价却不足3万元目前,随着我国国六排放法规的全面落实,越来越多的新能源车型出现在我们的视野当中,而其中微型车凭借小巧的身姿,低廉的售价深受消费者喜爱,像五菱宏光MINIEV,比亚迪e1,奔奔ESt3月1日微信支付宝新规,这些人或将无法收到转账,望周知本文原创,禁止抄袭,违者必究!曾经的移动支付很方便,往后的移动支付会很复杂?新规实行之后,这些人或将无法收到转账?关注科技圈的朋友可能知道,自3月1日起,个人收款码将不能用于经营收古人的智慧,通过谚语阐述,把世人看透的明明白白人情似纸张张薄,世事如棋局局新。贫居闹市无人问,富在深山有远亲。不信但看宴中酒,杯杯先敬富贵人。门前拴上高头马,不是亲来也是亲。门前放根讨饭棍,亲戚故友不上门。世人结交需黄金,黄金冬寒随风去,万事皆可期二月的阳光很暖,带着春的气息扑面而来,像母亲温柔的大手,抚慰着我的脸颊,从身到心温暖而醉人,自在而舒心,暖暖地都是幸福的味道。我总是喜欢在这明媚的午后阳光里坐在阳台上,泡一杯清茶,
海洋新物种能吸碳,每年1。5亿吨,可能是对抗全球变暖秘密武器(科学家发现了一种海洋生物,可能是对抗气候变化的秘密武器。)科学家们发现了一种新的小型海洋捕食者,它能够吸收碳。随着海洋变暖变酸,这种单细胞微生物可能是对抗气候变化的秘密武器。英国新研究观察到夏威夷珊瑚对海洋变暖表现出的惊人适应力一项对夏威夷珊瑚物种的长期研究提供了一个令人惊讶的乐观观点,即它们如何在气候变化导致的更温暖和更酸性的海洋中生存。研究人员发现,在模拟未来预期的海洋温度和酸度的条件下,被研究的三个视点丨肃北草原上的那达慕,是雪山蒙古族欢乐的海洋那达慕是蒙古语,亦称那雅尔(Nair),意为娱乐游戏,表示丰收的喜悦之情。肃北是甘肃省唯一以蒙古族为主体的少数民族自治县,那达慕是肃北每年最盛大的民间传统节日,其前身是蒙古族祭敖包重张半年的龙潭中湖公园湖水怎么见底了?正实施清淤工作天气回暖,眼下正是游园踏春的好时节。最近本报接到读者反映,龙潭中湖公园内的湖面水位大幅下降,多处湖水断流,露出了干涸的湖床。前身为北京游乐园的龙潭中湖公园,是去年十一前夕才重张开园特斯拉比亚迪领衔,新能源车迎二次涨价潮特斯拉5天内两度涨价比亚迪3月15日再次上调多款车价格从去年年底初露苗头的新能源汽车涨价潮仍在继续。近期,受国际大宗商品价格上涨叠加补贴退坡等影响,据不完全统计,仅3月份以来,已经骁龙778G4100毫安电池4088元起,你是怎样评价华为P50E的?2022年3月16号,华为举办了一场新品发布会。在这场新品发布会里华为带来了多款产品,包括手机平板智能音箱甚至还有汽车。但其中最有争议的一款产品应该是华为P50E,这是一款配置定位石清华原创丨砍倒圣诞树(随笔)砍倒圣诞树(随笔)文石清华人类文明发展到现在,已经处于知识大爆炸的岁月,快捷的传播将爆炸的信息塞满天地间的每一个角落。今天的很多人,都有这群那群这粉丝那粉丝,大朋友圈小朋友圈男朋友新能源汽车续航里程何时不再雾里看花?来源曲靖日报掌上曲靖购车时厂家宣传续航里程是420公里,销售说最少也能开到350公里,但实际最多只能开到300公里。2020年购买了一台新能源汽车的北京陈女士说,冬季的时候这个问题夜晚住到酒店最高层,俯瞰自己熟悉而陌生的城市置身于涌动的人潮之中,穿梭于钢筋混凝土的高楼之中,我们好像已经习惯自己是这个城市的一部分。可是忘记了吗?我们每天走的,不过是重复的一条路线我们每天经历的,不过是大同小异的人生。早晨血压不稳定,夏天不高冬天高冬天吃点阿司匹林预防脑梗可以吗阿司匹林在目前心血管领域是炙手可热的药物,心梗,脑梗的患者几乎人人离不开阿司匹林,阿司匹林的作用是通过抑制血小板聚集而抑制血栓形成,从而防止冠心病,缺血性卒中等动脉粥样硬化性心血管2022南北湖门票免费吗(附免费政策游玩攻略)三面环山,一面临江,风光独特,美景无限南北湖,一个坐拥山水美景以及丰富人文的风景名胜,这里气候适宜,拥有丰富的动植物资源,还是一处远离喧嚣的天然氧吧!南北湖门票免费吗?跟随小编看看