Sercurity + Auth2框架實(shí)現(xiàn)認(rèn)證授權(quán)

SpringSecurity 是Spring家族的一員赡矢,是Spring家族提供的安全框架溅潜,提供認(rèn)證和授權(quán)功能肋演,最主要的是它提供了簡(jiǎn)單的使用方式抑诸,同時(shí)又有很高的靈活性,簡(jiǎn)單爹殊,靈活蜕乡,強(qiáng)大。

主要的主要的幾個(gè)配置類

自定義Security的策略

AuthorizationServerConfigurerAdapter

例子如下:

@Configuration

@EnableAuthorizationServer

public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

@Override

? ? public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

? ? ? ? endpoints

? ? ? ? ? ? ? ? .authenticationManager(authenticationManager)

? ? ? ? ? ? ? ? .tokenGranter(new CompositeTokenGranter(getTokenGranters(endpoints)))

? ? ? ? ? ? ? ? .userDetailsService(userDetailsService)

? ? ? ? ? ? ? ? .tokenStore(tokenStore());

}

@Override

? ? public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

? ? ? ? //存放到db

? ? ? ? clients.jdbc(dataSource);

//? ? ? ? 存放到內(nèi)存

? ? ? ? clients.inMemory()

? ? ? ? ? ? ? ? .withClient("webapp")

? ? ? ? ? ? ? ? .secret(pass)

? ? ? ? ? ? ? ? .scopes("server")

? ? ? ? ? ? ? ? .authorizedGrantTypes("password", "authorization_code", "refresh_token")

? ? ? ? ? ? ? ? .accessTokenValiditySeconds(24 * 60 * 60) //token有效期

? ? ? ? ? ? ? ? .refreshTokenValiditySeconds(24 * 60 * 60)

? ? ? ? ? ? ? ? .and().withClient("app")

? ? ? ? ? ? ? ? .secret(pass)

? ? ? ? ? ? ? ? .scopes("app")

? ? ? ? ? ? ? ? .authorizedGrantTypes("authorization_code", "refresh_token")

? ? ? ? ? ? ? ? .redirectUris("https://www.baidu.com/");

? ? }

/**

? ? * 填充認(rèn)證方式

? ? * @param endpoints endpoints

? ? * @return list

? ? */

? ? private List<TokenGranter> getTokenGranters(AuthorizationServerEndpointsConfigurer endpoints) {

? ? ? ? AuthorizationServerTokenServices tokenServices = endpoints.getTokenServices();

? ? ? ? ClientDetailsService clientDetailsService = endpoints.getClientDetailsService();

? ? ? ? OAuth2RequestFactory oAuth2RequestFactory = endpoints.getOAuth2RequestFactory();

? ? ? ? AuthorizationCodeServices authorizationCodeServices = endpoints.getAuthorizationCodeServices();

? ? ? ? return new ArrayList<>(Arrays.asList(

? ? ? ? ? ? ? ? new RefreshTokenGranter(tokenServices, clientDetailsService, oAuth2RequestFactory),

? ? ? ? ? ? ? ? new AuthorizationCodeTokenGranter(tokenServices, authorizationCodeServices, clientDetailsService,

? ? ? ? ? ? ? ? ? ? ? ? oAuth2RequestFactory),

? ? ? ? ? ? ? ? new ResourceOwnerPasswordTokenGranter(authenticationManager, endpoints.getTokenServices(),

? ? ? ? ? ? ? ? ? ? ? ? clientDetailsService, oAuth2RequestFactory),

? ? ? ? ? ? ? ? new MyAbstractTokenGranter(authenticationManager, tokenServices, clientDetailsService,

? ? ? ? ? ? ? ? ? ? ? ? oAuth2RequestFactory)));

? ? }

}


默認(rèn)情況下spring?security?oauth?的http配置边灭。

ResourceServerConfigurerAdapter:

例子如下

@Configuration

@EnableResourceServer

public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

? ? @Override

? ? public void configure(HttpSecurity http) throws Exception {

? ? ? ? http

? ? ? ? ? ? ? ? .csrf().disable()

? ? ? ? ? ? ? ? .exceptionHandling()

? ? ? ? ? ? ? ? .authenticationEntryPoint((request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED))

? ? ? ? ? ? ? ? .and()

? ? ? ? ? ? ? ? .authorizeRequests()

? ? ? ? ? ? ? ? .antMatchers("/index/getUser").permitAll()

? ? ? ? ? ? ? ? .antMatchers("/user/getUserPassword").permitAll()

? ? ? ? ? ? ? ? .anyRequest().authenticated()

? ? ? ? ? ? ? ? .and()

? ? ? ? ? ? ? ? .httpBasic();

? ? }

}

WebSecurityConfigurerAdapter 類是個(gè)適配器, 需要配置的時(shí)候需要我們自己寫個(gè)配置類去繼承,根據(jù)自己的需求去進(jìn)行配置即可WebSecurityConfigurerAdapter的配置攔截要優(yōu)先于ResourceServerConfigurerAdapter异希,優(yōu)先級(jí)高的http配置是可以覆蓋優(yōu)先級(jí)低的配置的。

WebSecurityConfigurerAdapter

例子如下:

@Configuration

@EnableWebSecurity

public class SecurityConfig extends WebSecurityConfigurerAdapter {

? ? /**

? ? * 自定義實(shí)現(xiàn)用戶信息獲取

? ? *

? ? * @return

? ? */

? ? @Bean

? ? @Override

? ? public UserDetailsService userDetailsService() {

? ? ? ? return new MyUserDetailsServiceImpl();

? ? }

? ? /**

? ? * @param auth

? ? * @throws Exception

? ? */

? ? @Override

? ? protected void configure(AuthenticationManagerBuilder auth) throws Exception {

? ? ? ? auth.userDetailsService(userDetailsService())

? ? ? ? ? ? ? ? .passwordEncoder(passwordEncoder());

? ? }

? ? /**

? ? * @param http

? ? * @throws Exception

? ? */

? ? @Override

? ? protected void configure(HttpSecurity http) throws Exception {

? ? ? ? http.csrf().disable()

? ? ? ? ? ? ? ? .authorizeRequests().anyRequest().authenticated()

? ? ? ? ? ? ? ? .and()

? ? ? ? ? ? ? ? .httpBasic();

? ? }

? ? /**

? ? * 不定義沒有password grant_type

? ? */

? ? @Override

? ? @Bean

? ? public AuthenticationManager authenticationManagerBean() throws Exception {

? ? ? ? return super.authenticationManagerBean();

? ? }

? ? /**

? ? * 密碼解析器

? ? * @return PasswordEncoder

? ? */

? ? @Bean

? ? public PasswordEncoder passwordEncoder() {

? ? ? ? return new BCryptPasswordEncoder();

? ? }

}

繼承了抽象類 AbstractTokenGranter

AbstractTokenGranter

public class MyAbstractTokenGranter extends AbstractTokenGranter {

? ? @Autowired

? ? private UserInfo userInfo;

? ? @Autowired

? ? private RedisUtil redisUtil;

? ? private static final String GRANT_TYPE = "sms_cod";

? ? private final AuthenticationManager authenticationManager;

? ? public MyAbstractTokenGranter(AuthenticationManager authenticationManager,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AuthorizationServerTokenServices tokenServices,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ClientDetailsService clientDetailsService,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OAuth2RequestFactory requestFactory) {

? ? ? ? this(authenticationManager, tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);

? ? }

? ? protected MyAbstractTokenGranter(AuthenticationManager authenticationManager,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AuthorizationServerTokenServices tokenServices,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ClientDetailsService clientDetailsService,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OAuth2RequestFactory requestFactory, String grantType) {

? ? ? ? super(tokenServices, clientDetailsService, requestFactory, grantType);

? ? ? ? this.authenticationManager = authenticationManager;

? ? }

? ? /**

? ? * 我們拿到的 token 終會(huì)過(guò)期的, 對(duì)應(yīng)于刷新 token模式的 RefreshTokenGranter 則負(fù)責(zé)獲取新的 OAuth2AccessToken绒瘦。

? ? *

? ? * @param client

? ? * @param tokenRequest

? ? * @return

? ? */

? ? @Override

? ? protected OAuth2AccessToken getAccessToken(ClientDetails client, TokenRequest tokenRequest) {

? ? ? ? // 傳入的參數(shù)需要有 refresh_token (DefaultOAuth2AccessToken 中有 refreshToken 字段)

? ? ? ? String refreshToken = tokenRequest.getRequestParameters().get("refresh_token");

? ? ? ? // 調(diào)用 tokenService 的刷新方法得到新的 OAuth2AccessToken

? ? ? ? return getTokenServices().refreshAccessToken(refreshToken, tokenRequest);

? ? }

? ? /**

? ? * 用戶攔截

? ? *

? ? * @param client? ? ? client

? ? * @param tokenRequest 請(qǐng)求的令牌

? ? * @return

? ? */

? ? @Override

? ? protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {

? ? ? ? Map<String, String> parameters = new LinkedHashMap<String, String>(tokenRequest.getRequestParameters());

? ? ? ? String username = parameters.get("username");

? ? ? ? String password = parameters.get("password");

? ? ? ? String mobile = parameters.get("mobile");

? ? ? ? //客戶端提交的驗(yàn)證碼

? ? ? ? String smscode = parameters.get("sms_cod");

? ? ? ? String type = parameters.get("type");

? ? ? ? parameters.remove("password");

? ? ? ? //驗(yàn)證用戶狀態(tài)(是否警用等)

//? ? ? ? UserInfo userInfo = new UserInfo();

//? ? ? ? userInfo.setMobile(mobile);

? ? ? ? // 驗(yàn)證驗(yàn)證碼

? ? ? ? //獲取服務(wù)中保存的用戶驗(yàn)證碼

? ? ? ? String smsCheckCode = (String) redisUtil.get(userInfo.getMobile());

? ? ? ? if (StringUtils.isBlank(smsCheckCode)) {

? ? ? ? ? ? throw new InvalidGrantException("用戶沒有發(fā)送驗(yàn)證碼");

? ? ? ? }

? ? ? ? if (!smscode.equals(smsCheckCode)) {

? ? ? ? ? ? throw new InvalidGrantException("驗(yàn)證碼不正確");

? ? ? ? } else {

? ? ? ? ? ? //驗(yàn)證通過(guò)后從緩存中移除驗(yàn)證碼

? ? ? ? ? ? redisUtil.setRemove(userInfo.getMobile(), smsCheckCode);

? ? ? ? }

? ? ? ? if (username.isEmpty()) {

? ? ? ? ? ? throw new InvalidGrantException("用戶不存在");

? ? ? ? }

? ? ? ? Authentication userAuth = new UsernamePasswordAuthenticationToken(username, password);

? ? ? ? ((AbstractAuthenticationToken) userAuth).setDetails(parameters);

? ? ? ? try {

? ? ? ? ? ? userAuth = authenticationManager.authenticate(userAuth);

? ? ? ? } catch (AccountStatusException ase) {

? ? ? ? ? ? //covers expired, locked, disabled cases (mentioned in section 5.2, draft 31)

? ? ? ? ? ? throw new InvalidGrantException(ase.getMessage());

? ? ? ? } catch (BadCredentialsException e) {

? ? ? ? ? ? // If the username/password are wrong the spec says we should send 400/invalid grant

? ? ? ? ? ? throw new InvalidGrantException(e.getMessage());

? ? ? ? }

? ? ? ? if (userAuth == null || !userAuth.isAuthenticated()) {

? ? ? ? ? ? throw new InvalidGrantException("Could not authenticate user: " + username);

? ? ? ? }

? ? ? ? OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);

? ? ? ? return new OAuth2Authentication(storedOAuth2Request, userAuth);

? ? }

核心依賴配置配置如下:

<dependency>

? ? ? ? ? ? <groupId>org.springframework.security.oauth</groupId>

? ? ? ? ? ? <artifactId>spring-security-oauth2</artifactId>

? ? ? ? ? ? <version>${oauth2.version}</version>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.springframework.cloud</groupId>

? ? ? ? ? ? <artifactId>spring-cloud-starter-security</artifactId>

? ? ? ? ? ? <exclusions>

? ? ? ? ? ? ? ? <!--舊版本 redis操作有問(wèn)題-->

? ? ? ? ? ? ? ? <exclusion>

? ? ? ? ? ? ? ? ? ? <artifactId>spring-security-oauth2</artifactId>

? ? ? ? ? ? ? ? ? ? <groupId>org.springframework.security.oauth</groupId>

? ? ? ? ? ? ? ? </exclusion>

? ? ? ? ? ? </exclusions>

使用SpringSrcurity+Anut2根據(jù)token實(shí)現(xiàn)用戶密碼登錄

service層

/**

? ? * 根據(jù)用戶名查詢

? ? * @param userName 用戶名

? ? * @return 返回的路徑

? ? */

? ? UserInfo getUserInfoByName(@Param("userName") String userName);

Service層

@Service

public class MyUserDetailsServiceImpl implements UserDetailsService {

? ? @Autowired

? ? public PasswordEncoder passwordEncoder;

? ? @Resource

? ? private UserInfoService userInfoService;

? ? @Resource

? ? private UserInfoMapper userInfoMapper;

? ? @Override

? ? public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

? ? ? ? UserInfo userInfo = userInfoService.getUserInfoByName(username);

? ? ? ? if (userInfo == null){

? ? ? ? ? ? throw new UsernameNotFoundException(username);

? ? ? ? }

? ? ? ? return userInfo;

? ? }

Controlleer層

@RestController

@RequestMapping("/")

public class IndexController {

? ? /**

? ? * user

? ? * @param user user

? ? * @return Principal

? ? */

? ? @GetMapping(value = "/user")

? ? public Principal user(Principal user) {

? ? ? ? return user;

? ? }

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末称簿,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子惰帽,更是在濱河造成了極大的恐慌憨降,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件该酗,死亡現(xiàn)場(chǎng)離奇詭異授药,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)呜魄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門悔叽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人爵嗅,你說(shuō)我怎么就攤上這事娇澎。” “怎么了睹晒?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵趟庄,是天一觀的道長(zhǎng)括细。 經(jīng)常有香客問(wèn)我,道長(zhǎng)戚啥,這世上最難降的妖魔是什么奋单? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮猫十,結(jié)果婚禮上览濒,老公的妹妹穿的比我還像新娘。我一直安慰自己炫彩,他們只是感情好匾七,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布絮短。 她就那樣靜靜地躺著江兢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪丁频。 梳的紋絲不亂的頭發(fā)上杉允,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音席里,去河邊找鬼叔磷。 笑死,一個(gè)胖子當(dāng)著我的面吹牛奖磁,可吹牛的內(nèi)容都是我干的改基。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼咖为,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼秕狰!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起躁染,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤鸣哀,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后吞彤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體我衬,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年饰恕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了挠羔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡埋嵌,死狀恐怖破加,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情莉恼,我是刑警寧澤拌喉,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布速那,位于F島的核電站,受9級(jí)特大地震影響尿背,放射性物質(zhì)發(fā)生泄漏端仰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一田藐、第九天 我趴在偏房一處隱蔽的房頂上張望荔烧。 院中可真熱鬧,春花似錦汽久、人聲如沸鹤竭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)臀稚。三九已至,卻和暖如春三痰,著一層夾襖步出監(jiān)牢的瞬間吧寺,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工散劫, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留稚机,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓获搏,卻偏偏與公主長(zhǎng)得像赖条,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子常熙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345